Android 使用 Gradle 多渠道打包

Posted cxchanpin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 使用 Gradle 多渠道打包相关的知识,希望对你有一定的参考价值。

安卓开发完毕。对于一个开放应用而言,我们须要公布到不同的应用市场,同一时候我们也须要统计不同市场的用户下载量。

(通过启动应用后获取不同市场apk中的不同值来区分)

以下用一个详细的实例来说明:
1、在androidManifest.xml的application内加入meta-data标签

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name">

    <meta-data
        android:name="APP_CHANNEL"
        android:value="${APP_CHANNEL_VALUE}" />

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

2、改动build.gradle文件,在android {} 中加入

android {

    // 打包渠道List
    productFlavors {
        wandoujia {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "豌豆荚"]
        }
        cn360 {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "360"]
        }
        baidu {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "百度"]
        }
        tencent {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "应用宝"]
        }
        sougou {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "搜狗市场"]
        }
    }

}

或者使用以下方法,直接使用flavor的name做为${APP_CHANNEL_VALUE}

android {

    // 打包渠道List
    productFlavors {
        wandoujia {}
        cn360 {}
        baidu {}
        tencent {}
        sougou {}
    }

    // 批量处理,直接使用flavor的name作为APP_CHANNEL_VALUE的值
    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [APP_CHANNEL_VALUE: name]
    }

}

这样就完毕了。运行 gradle assembleRelease 喝口茶坐等便可。
完毕后,到build/outputs/apk中就能够看到各种渠道包。

有关assemble可用的命令还有:

gradle assembleDebug    //全部Debug版本号
gradle assembleRelease  //全部Release版本号
gradle assembleBaidu    //指定渠道的DebugRelease版本号
gradle assembleBaiduDebug   //指定渠道的Debug版本号
gradle assembleBaiduRelease //指定渠道的Release版本号
gradle build    //全部渠道的DebugRelease版本号

最后附上我的 MainActivity 和 build.gradle

package com.example.myandroid;

import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.widget.Toast;

/**
 * 应用入口
 *
 * @author SHANHY([email protected])
 * @date   2015年12月30日
 */
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String channel = getAppMetaData("APP_CHANNEL");
        if(channel != null)
            Toast.makeText(this, channel, Toast.LENGTH_SHORT).show();
    }

    /**
     * 获取Application以下的metaData
     * 
     * @param name
     * @return
     * @author SHANHY
     * @date   2015年12月30日
     */
    public String getAppMetaData(String meta_name){
        try {
            ApplicationInfo appInfo = this.getPackageManager()
                    .getApplicationInfo(getPackageName(),PackageManager.GET_META_DATA);
            return appInfo.metaData.getString(meta_name);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

完整的 build.gradle 脚本

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath ‘com.android.tools.build:gradle:2.0.0-alpha3‘
    }
}

apply plugin: ‘com.android.application‘

dependencies {
    compile fileTree(dir: ‘libs‘, include: ‘*.jar‘)
}

android {
    compileSdkVersion 14
    buildToolsVersion "23.0.2"

    defaultConfig {
        // 能够手动改动例如以下一些配置。无需改动不论什么代码便能够生成相应配置的apk
        applicationId "com.example.myandroid.aaa"
        minSdkVersion 8
        targetSdkVersion 21
        versionCode 200
        versionName "2.0.0"

        // dex突破65535限制
        multiDexEnabled true
        // 默认打包渠道(官方)
        manifestPlaceholders = [APP_CHANNEL_VALUE: "官方"]
    }

    // 打包渠道List
    productFlavors {
        myself {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "官方"]
        }
        wandoujia {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "豌豆荚"]
        }
        cn360 {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "360"]
        }
        baidu {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "百度"]
        }
        tencent {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "应用宝"]
        }
        sougou {
            manifestPlaceholders = [APP_CHANNEL_VALUE: "搜狗市场"]
        }
    }

    // 打包渠道List
    //productFlavors {
    //  myself {}
    //  wandoujia {}
    //  cn360 {}
    //  baidu {}
    //  tencent {}
    //  sougou {}
    //}

    // 批量处理,直接使用flavor的name作为APP_CHANNEL_VALUE的值(也能够不使用该方法,在productFlavors中逐一配置)
    //productFlavors.all { flavor ->
    //  flavor.manifestPlaceholders = [APP_CHANNEL_VALUE: name]
    //}

    lintOptions {
        abortOnError false
    }

    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‘)

        // 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(‘build-types/debug‘)
        release.setRoot(‘build-types/release‘)
    }

    //签名信息
    signingConfigs {
        debug{
            // No Debug Config
        }

        release {
            storeFile file("xxxxx.key")
            storePassword "xxxxx"
            keyAlias "xxxxx"
            keyPassword "xxxxx"
        }
    }
    buildTypes {
        //Debug模式
        debug {
            // 显示LOG,在java代码中的调用方式为:BuildConfig.LOG_DEBUG。AS工具能够在BuildConfig.java中新增这个字段,假设还要兼容使用eclipse,不建议使用新增字段,由于eclipse在clean后会又一次生成BuildConfig.java(默认使用BuildConfig.DEBUG能满足须要就不要特殊处理了)
            //buildConfigField "boolean", "LOG_DEBUG", "true"

            versionNameSuffix "-debug"
            // 不开启混淆
            minifyEnabled false
            // 不须要ZIP优化
            zipAlignEnabled false
            // 不须要资源压缩
            shrinkResources false
            // signingConfig 
            signingConfig signingConfigs.debug
        }

        //Release模式
        release {
            // 不显示LOG
            //buildConfigField "boolean", "LOG_DEBUG", "true"

            minifyEnabled true
            zipAlignEnabled true
            // 资源压缩,移除没用的资源文件
            shrinkResources true
            // 混淆文件配置
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
            // 签名信息配置(假设上面配置了defaultConfig则能够不用指定signingConfig)
            signingConfig signingConfigs.release

            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith(‘.apk‘)) {
                        // 输出apk名称为myandroid_v1.0.0_2015-12-30_baidu.apk
                        def fileName = "myandroid_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }
    }
}

// 声明一个方法,获取打包时间
def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

以上是关于Android 使用 Gradle 多渠道打包的主要内容,如果未能解决你的问题,请参考以下文章

android -------- Gradle 多渠道打包

Gradle实战:Android多渠道打包方案汇总

Android Studio + gradle多渠道打包

Android gradle实现多渠道号打包

ANDROID STUDIO系列教程六--GRADLE多渠道打包

Android 多渠道打包