最近在学习撸撸的代码规范和写法,有些心得,准备好好写一写~包括了多渠道打版(以前有写过方法),工厂模式,mvp,以及最近刚封装出来的多渠道多版本展示不同页面的manifestPlaceholders的配置方法,大家应该也碰到过线上和线下环境的切换换地址,换私钥的头大问题,本篇就来解决这些问题。
先在androidmanifest文件配置一个节点,这里以极光为例:
1
2
3
4
5
6
7
|
<meta-data
android:name=
"JPUSH_APPKEY"
android:value=
"${jush_appkey_value}"
/>
<meta-data
android:name=
"SHOUCANG_CONFIG0"
android:value=
"${SHOUCANG_CONFIG_VALUE0}"
/>
|
build.gradle:
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
|
buildTypes {
release {
//自定义buildconfig字段
buildConfigField(
"boolean"
,
"APP_ENV"
,
"true"
)
//指定签名为release
signingConfig signingConfig.release
//是否开启混淆
minifyEnabled
false
proguardFiles getDefaultProguardFile(
'proguard-android.txt'
),
'proguard-rules.pro'
//是否zip优化
zipAlignEnabled
true
//删除一些无用资源
shrinkResources
false
//
manifestPlaceholders = [
"jush_appkey_value"
:
"release key"
]
}
debug {
//自定义buildconfig字段
buildConfigField(
"boolean"
,
"APP_ENV"
,
"true"
)
//指定签名为release
signingConfig signingConfig.release
//是否开启混淆
minifyEnabled
false
proguardFiles getDefaultProguardFile(
'proguard-android.txt'
),
'proguard-rules.pro'
//是否zip优化
zipAlignEnabled
true
//删除一些无用资源
shrinkResources
false
//
manifestPlaceholders = [
"jush_appkey_value"
:
"debug key"
]
}
}
|
在bulidtypes节点下有release节点和debug节点,正式签名时就会走release节点的下编译脚本,调试签名时就会走debug节点。主要点就是manifestPlaceholders的用法,jpush_appkey对应的就是之前在androidmanifest文件配置的${jush_appkey_value}的这个值。
在程序入口出打上log,用来输出key的值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 在程序入口出打上log,用来输出key的值bufen
*/
private
void
jpush_key_manifest_xml_string() {
String jpush_appkey;
try
{
ApplicationInfo appInfo = getPackageManager()
.getApplicationInfo(getPackageName(),
PackageManager.GET_META_DATA);
jpush_appkey = appInfo.metaData.getString(
"JPUSH_APPKEY"
);
Log.e(
"jpush_appkey"
,
"jpush_appkey="
+ jpush_appkey);
}
catch
(PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
|
接下来给大家介绍多版本多页面多apk的配置切换方法:举个例子:如果你要一次性打七个版本,而且七个版本都是不同的页面,但是页面各个模块大体一样,只是顺序和大小不同,你要怎么做,别告诉我写七个页面分别打版哈~太low了~you know~这里就利用多版本打版和manifestPlaceholders来实现需求。
首先是build.gradle:
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
|
apply plugin:
'com.android.application'
apply plugin:
'android-apt'
def demo =
'0000'
;
//DemoAPK
def demo1 =
'0001'
;
//DemoAPK1
def demo2 =
'0002'
;
//DemoAPK2
def demo3 =
'0003'
;
//DemoAPK3
def demo4 =
'0004'
;
//DemoAPK4
def demo5 =
'0005'
;
//DemoAPK5
def demo6 =
'0006'
;
//DemoAPK6
android {
signingConfigs {
debug {
keyAlias
'****'
keyPassword
'****'
storeFile file(
'签名文件.jks路径'
)
storePassword
'****'
}
release {
keyAlias
'****'
keyPassword
'****'
storeFile file(
'签名文件.jks路径'
)
storePassword
'****'
}
}
compileSdkVersion
25
buildToolsVersion
"25.0.2"
sourceSets {
main {
jniLibs.srcDirs = [
'libs'
]
}
}
packagingOptions {
exclude
'META-INF/DEPENDENCIES'
exclude
'META-INF/NOTICE'
exclude
'META-INF/LICENSE'
exclude
'META-INF/LICENSE.txt'
exclude
'META-INF/NOTICE.txt'
}
defaultConfig {
applicationId
"com.shining.p010_recycleviewall"
minSdkVersion
18
targetSdkVersion
23
versionCode
1
versionName
"1.0"
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
//LOCAL_LDFLAGS += -fuse-ld=bfd
//jni.srcDirs 'src/main/jni'
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
manifestPlaceholders = [
SHOUCANG_CONFIG_VALUE0:
".shoucang.factorys.ShoucangFactory0"
]
}
buildTypes {
release {
minifyEnabled
true
zipAlignEnabled
true
shrinkResources
false
proguardFiles getDefaultProguardFile(
'proguard-android.txt'
),
'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
def
int
minSdk =
18
;
def
int
targetSdk =
23
;
def String appId =
'com.shining.p010_recycleviewall'
;
def
int
vCode =
1
;
def String vNameCode = vCode +
""
;
productFlavors {
//demo
DemoAPK {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK_"
+
"T_"
+ demo
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
//demo1
DemoAPK1 {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK1_"
+
"T_"
+ demo1
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
//demo2
DemoAPK2 {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK2_"
+
"T_"
+ demo2
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
//demo3
DemoAPK3 {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK3_"
+
"T_"
+ demo3
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
//demo4
DemoAPK4 {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK4_"
+
"T_"
+ demo4
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
//demo5
DemoAPK5 {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK5_"
+
"T_"
+ demo5
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
//demo6
DemoAPK6 {
minSdkVersion minSdk
applicationId appId
targetSdkVersion targetSdk
versionCode vCode
versionName
"DemoAPK6_"
+
"D_"
+ demo6
multiDexEnabled
true
renderscriptTargetApi
19
renderscriptSupportModeEnabled
true
ndk {
moduleName
"native-modbus-jni,libxmediaplayer"
ldLibs
"log"
,
"z"
,
"m"
,
"android"
,
"c"
abiFilters
"armeabi"
,
"armeabi-v7a"
,
"x86"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir
'src/main/libs'
}
signingConfig signingConfigs.debug
}
}
// 自定义输出配置
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if
(outputFile !=
null
&& outputFile.name.endsWith(
'.apk'
)) {
// def fileName = "UerbT_v${variant.versionName}_${releaseTime()}_${variant.flavorName}.apk"
def fileName =
"${variant.versionName}.apk"
output.outputFile =
new
File(outputFile.parent, fileName)
}
}
}
productFlavors.all { flavor ->
def currentMode = flavor.versionName.split(
"_"
)[
2
]
def currentEnvironment = flavor.versionName.split(
"_"
)[
1
]
def stValue =
true
// t == currentEnvironment 以前的判断条件
if
(currentEnvironment.endsWith(
"T"
)) {
//判断是否为测试版 是否以T结尾
stValue =
false
}
else
{
stValue =
true
}
if
(currentMode == demo) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory"
, STATISTICS_VALUE: stValue]
}
else
if
(currentMode == demo1) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory1"
, STATISTICS_VALUE: stValue]
}
else
if
(currentMode == demo2) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory2"
, STATISTICS_VALUE: stValue]
}
else
if
(currentMode == demo3) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory3"
, STATISTICS_VALUE: stValue]
}
else
if
(currentMode == demo4) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory4"
, STATISTICS_VALUE: stValue]
}
else
if
(currentMode == demo5) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory5"
, STATISTICS_VALUE: stValue]
}
else
if
(currentMode == demo6) {
flavor.manifestPlaceholders = [SHOUCANG_CONFIG_VALUE:
".shoucang.factorys.ShoucangFactory6"
, STATISTICS_VALUE: stValue]
}
}
}
dependencies {
compile fileTree(include: [
'*.jar'
], dir:
'libs'
)
androidTestCompile(
'com.android.support.test.espresso:espresso-core:2.2.2'
, {
exclude group:
'com.android.support'
, module:
'support-annotations'
})
compile
'com.android.support:appcompat-v7:25.3.0'
compile
'com.android.support:recyclerview-v7:25.3.0'
compile
'com.android.support:design:25.3.0'
compile
'com.android.support:cardview-v7:25.3.0'
// local jar file
compile files(
'libs/alipay-sdk-java20161226110022.jar'
)
compile files(
'libs/alipay-sdk-java20161226110022-source.jar'
)
compile files(
'libs/commons-logging-1.1.1.jar'
)
compile files(
'libs/commons-logging-1.1.1-sources.jar'
)
//the third file
compile
'com.jakewharton:butterknife:8.2.1'
apt
'com.jakewharton:butterknife-compiler:8.2.1'
testCompile
'junit:junit:4.12'
compile
'com.geeklx:library_hios:1.0.4'
compile project(
':glin'
)
compile
'com.github.bumptech.glide:glide:3.7.0'
compile
'com.alibaba:fastjson:1.2.17'
compile
'com.squareup.okio:okio:1.9.0'
compile
'com.squareup.okhttp3:okhttp:3.4.1'
compile
'com.nineoldandroids:library:2.4.0'
compile files(
'libs/libammsdk.jar'
)
}
|
接着就是多版本的代码判断书写:
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
|
@Override
protected
void
onCreate(
@Nullable
Bundle savedInstanceState) {
//TODO 多版本切换 写此方法bufen
which_version();
// ShoucangConfig0.config();//manifestPlaceholders的妙用
super
.onCreate(savedInstanceState);
}
private
void
which_version() {
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name0) {
ShoucangConfig.config();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name1) {
ShoucangConfig1.config();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name2) {
ShoucangConfig2.config();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name3) {
ShoucangConfig3.config();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name4) {
ShoucangConfig4.config();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name5) {
ShoucangConfig5.config();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name6) {
ShoucangConfig6.config();
}
}
//TODO 多版本模式bufen
SparseArrayCompat<Class<?
extends
BaseFragment>> array = which_version_fragment_config();
//demo
private
SparseArrayCompat<Class<?
extends
BaseFragment>> which_version_fragment_config() {
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name0) {
return
ShoucangConfig.getFragments();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name1) {
return
ShoucangConfig1.getFragments();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name2) {
return
ShoucangConfig2.getFragments();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name3) {
return
ShoucangConfig3.getFragments();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name4) {
return
ShoucangConfig4.getFragments();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name5) {
return
ShoucangConfig5.getFragments();
}
else
if
(ConstantNetUtil.VERSION_APK == NetConfig.version_name6) {
return
ShoucangConfig6.getFragments();
}
return
ShoucangConfig.getFragments();
}
|
这样跑完apk你会发现会有神奇的事情发生,如下图:(不同的apk版本出来的页面也是不同的,但是只用了一份代码。)
图1:
图2:
这样做的好处在于,如果你的apk版本很多,需要给很多合作厂商提供定制化页面,就可以用上了~
卧槽,今天喷了好多,希望大家回去自己细化一下,能帮到你~