继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android Gradle打包基础

皈依舞
关注TA
已关注
手记 99
粉丝 13
获赞 37

Android gradle打包基础

gradle目录

[代码]java代码:

?

12345MyApp├── build.gradle ( 可以查看Gradle的版本 )├── settings.gradle( include不同的模块)└── app    └── build.gradle( 配置App模块的参数 )


混淆

Gradle signingConfigs基本配置

archiveNameFormat - Groovy格式字符串, 指定渠道打包输出的APK文件名格式,默认文件名格式是: ${appPkg}-${flavorName}-${buildType}-v${versionName}-${versionCode},可使用以下变量:

projectName - 项目名字
appName - App模块名字
appPkg - applicationId (App包名packageName)
buildType - buildType (release/debug/beta等)
flavorName - flavorName (对应渠道打包中的渠道名字)
versionName - versionName (显示用的版本号)
versionCode - versionCode (内部版本号)
buildTime - buildTime (编译构建日期时间)

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
android {
    compileSdkVersion 22 //编译版本
    buildToolsVersion "23.0.0" //buildtool版本

    defaultConfig {
	//默认配置,会同时应用到debug和release版本上
        applicationId "io.yimsamtam.***" //包名
        minSdkVersion 14
        targetSdkVersion 22
        versionCode 2
        versionName "1.2.0"
    }

    signingConfigs {
        release {//获取build.properties里的密码常量,需要在buildeTypes引用
            storeFile file(STORE_FILE)
            storePassword STORE_PASSWORD
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
        }
        debug {
            storeFile file(STORE_FILE)
            storePassword STORE_PASSWORD
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
        }

    }
    buildTypes {
	//这里面可以配置不同版本的一些参数,比如混淆、签名配置等
        release { //正式服 正式签名
            signingConfig signingConfigs.release //用keystore打包
            minifyEnabled true //是否开启混淆
            zipAlignEnabled true //压缩
            shrinkResources true //去掉无用的resourse文件
    		debuggable true //使该版本可调试
            buildConfigField "boolean", "LOG_DEBUG", "false"
			//加载混淆文件,开启混淆没有这句会报错
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }

        develop {//开发服 正式签名
            signingConfig signingConfigs.release
            minifyEnabled true
            zipAlignEnabled true
            shrinkResources true
            debuggable true //使该版本可调式
            buildConfigField "boolean", "LOG_DEBUG", "true"
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }
        debug { //测试服 测试签名
            signingConfig signingConfigs.debug
            minifyEnabled false
            zipAlignEnabled false
            // 移除无用的resource文件
            shrinkResources false
            buildConfigField "boolean", "LOG_DEBUG", "true"
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    //修改生成的最终文件名
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                File outputDirectory = new File(outputFile.parent);
                def fileName
                String channelName = "homepage";
                if (variant.buildType.name == "release") {
                    //输出:bnj_t_2015.12.12_4886faf_c360.apk

                    if (variant.productFlavors[0] != null) {
                        channelName = variant.productFlavors[0].name;
                    }
                    //版本+时间+git版本+渠道的格式
                    fileName = "Movie_${channelName}_${packageTime()}_${revision()}.apk"
                } else if (variant.buildType.name == "develop") {
                    //输出:bnj_t_2015.12.12_4886faf.apk
                    fileName = "Movie_${packageTime()}_${revision()}.apk"
                    //${defaultConfig.versionname}
                } else {
                    //输出:bnj_t_2015.12.12_4886faf_debug.apk
                    fileName = "Movie_debug.apk"
                }
                output.outputFile = new File(outputDirectory, fileName)
            }
        }
    }

    productFlavors {

        offcial {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "offcial"]
        }

        wandoujia {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }

        baidu {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
        }

    }

   //修改生成的最终文件名
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                File outputDirectory = new File(outputFile.parent);
                def fileName
                String channelName = "offcial";
                if (variant.buildType.name == "release") {
                    //输出:Movie_2015.12.12_4886faf_c360.apk

                    if (variant.productFlavors[0] != null) {
                        channelName = variant.productFlavors[0].name;
                    }
                    //版本+时间+git版本+渠道的格式
                    fileName = "Movie_${channelName}_${packageTime()}_${revision()}.apk"
                } else if (variant.buildType.name == "develop") {
                    //输出:bnj_t_2015.12.12_4886faf.apk
                    fileName = "Movie_Dev${packageTime()}_${revision()}.apk"
                    //${defaultConfig.versionname}
                } else {
                    //输出:bnj_t_2015.12.12_4886faf_debug.apk
                    fileName = "Movie_debug.apk"
                }
                output.outputFile = new File(outputDirectory, fileName)
            }
        }
    }


	lintOptions {//移除lint检查的error
			abortOnError false
	}

}

//找到文件的签名
File propFile = file('signing.properties');
if (propFile.exists()) {
    def Properties props = new Properties()
    props.load(new FileInputStream(propFile))
    if (props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&
            props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
        android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
        android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
        android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
        android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
    } else {
        android.buildTypes.release.signingConfig = null
    }
} else {
    android.buildTypes.release.signingConfig = null
}

dependencies {
//模块依赖
 compile group: '包名' , name: '模块名' , version: '版本号'
}  

// 打包时间格式
def packageTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

Mapping(/project/app/build/outputs/mapping/)

dump.txt 描述apk文件中所有类文件间的内部结构。
mapping.txt 列出了原始的类,方法,和字段名与混淆后代码之间的映射。
seeds.txt 列出了未被混淆的类和成员
usage.txt 列出了从apk中删除的代码


  • settings.gradle (声明加入工程的module)

include ‘:app’,’:module-b’ //示例

  • gradle.properties (保存应用签名密码等常量)

STORE_FILE = keystore(jks)的路径
STORE_PASSWORD = KEYSTORE密码
KEY_ALIAS = 别名
KEY_PASSWORD = KEYSTORE密码

会自动生成local.properties文件

  • 在build.gradle的android标签下引用

1
2
3
4
5
6
7
8
signingConfigs {  //获取应用签名的密码常量,需要在buildTypes里调用
	releaseConfig {
	storeFile file(STORE_FILE)
	storePassword STORE_PASSWORD
	keyAlias KEY_ALIAS
	keyPassword KEY_PASSWORD
	}
}

常见错误

1
If you are using Gradle, make sure that your current variant is debuggable.

原因及解决:Build Variant里该版本未开启调试功能。在Gradle里添加debugable true代码即可。

1
Error:Execution failed for task ':demo:packageRelease'.> Unable to compute hash of D:\testProject\demo\build\intermediates\classes-proguard\release\classes.jar

原因及解决:混淆了第三方jar包。注释掉 -libraryjars相关代码即可。

1
2
The APK file build\outputs\apk\******.apk does not exist on disk.
Error while Installing APK

原因及解决: 刷新一下Gradle或者Clean Project即可。

BuildConfig详解

当Android Studio编译的时候,会自动生成一个BuildConfig类。该类保存了一些Gradle里的常量。在Java代码中,可以通过该类来获取这些常量的值。

1
2
3
4
5
6
7
8
9
10
public final class BuildConfig {
	public static final boolean DEBUG = Boolean.parseBoolean("true");
	public static final String APPLICATION_ID = "io.movies"; //包名
	public static final String BUILD_TYPE = "develop";//发布类型
	public static final String FLAVOR = "offcial"; //渠道版本
	public static final int VERSION_CODE = 2;//版本号
	public static final String VERSION_NAME = "1.2.0";//版本名
	// Fields from build type: develop
	public static final boolean LOG_DEBUG = true; //自定义的Log关闭
}

当然我们还可以根据需要来自定义这些常量。例如根据发布类型来控制LOG是否输出。

首先,我们需要在BuildTypes不同发布类型里定义一个字段 ,从而控制其LOG输出。

1
2
3
4
5
6
7
8
9
10
11
12
buildtypes{

	release{
		buildConfigField "boolean","LOG_DEBUG","false"//关闭LOG输出
	}

	develop{
		buildConfigField "boolean","LOG_DEBUG","true" //打开LOG输出
	}

}

接着,在Log工具类里,通过BuildConfig类来获取LOG_DEBUG的值即可。

1
2
3
4
5
public class LogUtil {

    public static boolean ENABLE_LOG = BuildConfig.LOG_DEBUG;

}

Meta-data详解

Androidmanifest文件里meta-data标签主要用于提供组件额外的数据,本身是一个键值对,可以自定义键和值。(在打包的时候,可根据需要设置不同的值)

在Java中使用

首先判断Meta-data标签在哪个标签内,如果在application标签里,则需要用Applicationinfo来获取该值。同理,在Activity标签里,用ActivityInfo。

1
2
3
4
5
6
7
8
9
<application
	.
	.
	.
    <meta-data
        android:name="yimsamtam.github.io.test"
        android:value="YimSamTam" />

</application>

在Java代码用ApplicationInfo获取。

1
2
3
ApplicationInfo info = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
String value = info.metaData.getString("yimsamtam.github.io.test");
Functions.toast(this, value); //此处打印YimSamTam字符串

在Gradle中使用

Androidmanifest文件里,其值通过${KEY}的方式来引用。在Gradle里赋值。

1
2
3
4
5
6
7
8
9
<application
	.
	.
	.
    <meta-data
        android:name="yimsamtam.github.io.test"
        android:value="${TEST_VALUE}" />

</application>

在Gradle里结合manifestPlaceholders赋值

1
2
3
4
5
6
7
productFlavors {
    offcial {
        manifestPlaceholders = [TEST_VALUE: "YimSamTam"]
    }
}

//当程序编译offcial版本时,便会赋值YimSamTam到Androidmanifest文件的meta-data标签里。

实际开发需求-不同发布版本使用不同的友盟UMENG_APPKEY

Manifest代码如下

1
2
3
4
5
6
<application
    <meta-data
        android:name="UMENG_APPKEY"
        android:value="${UMENG_APPKEY}" />

</application>

Gradle代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildTypes {
    release { //正式服
        manifestPlaceholders = [UMENG_APPKEY: "570104fde0f55aedba00200d-REL"]
    }

    develop {//开发服
        manifestPlaceholders = [UMENG_APPKEY: "570104fde0f55aedba00200d-DEV"]

    }
    debug { //测试服
        manifestPlaceholders = [UMENG_APPKEY: "570104fde0f55aedba00200d-DEB"]
    }
}

通过meta-data定义Image

推荐

Android Gradle 获取 APK 签名状态及对齐状态

原文链接:http://www.apkbus.com/blog-705730-61586.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP