添加渠道标签
AndroidManifest.xml
1 2 3 4 <application > <meta-data android:value ="$ {UMENG_CHANNEL_VALUE} " android:name ="UMENG_CHANNEL" /></application >
添加渠道,签名
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 apply plugin: 'com.android.application' android { signingConfigs { release { } } compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "com.xuie.testgradle" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { signingConfig signingConfigs.release minifyEnabled true zipAlignEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt' ), 'proguard-rules.pro' } debug { debuggable true minifyEnabled false zipAlignEnabled true shrinkResources true } } productFlavors { xiaomi {} qihu360 {} baidu {} wandoujia {} } productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } 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 if (variant.buildType.name == "release" ) { fileName = "app_v${defaultConfig.versionName}_${buildTime()}_${variant.productFlavors[0].name}.apk" } else { fileName = "app_v${defaultConfig.versionName}_${buildTime()}_beta.apk" } output.outputFile = new File (outputDirectory, fileName) } } } } def Properties props = new Properties()def propFile = file ('../local.properties' )if (propFile.canRead()){ props.load(new FileInputStream(propFile)) if (props!=null && props.containsKey('STORE_FILE' ) && props.containsKey('STORE_PASSWORD' ) && props.containsKey('KEY_ALIAS' ) && props.containsKey('KEY_PASSWORD' )) { println 'RELEASE BUILD SIGNING' 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 { println 'RELEASE BUILD NOT FOUND SIGNING PROPERTIES' android.buildTypes.release.signingConfig = null } }else { println 'RELEASE BUILD NOT FOUND SIGNING FILE' android.buildTypes.release.signingConfig = null } def buildTime() { return new Date().format("yyyy-MM-dd" , TimeZone.getTimeZone("UTC" )) } def hostName() { return System.getProperty("user.name" ) + "@" + InetAddress.localHost.hostName } dependencies { compile fileTree (dir: 'libs' , include : ['*.jar' ]) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' }
独立配置签名
local.properties — 与build.gradle中的propFile相对应
1 2 3 4 KEY_ALIAS =[密钥别名]KEY_PASSWORD =[密钥密码]STORE_FILE =[/home/xuie/xuie0000.jks]STORE_PASSWORD =[签名文件密码]
混淆 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 ## 位于module 下的proguard-rules.pro ##################################### ######### 主程序不能混淆的代码 ######### ##################################### #-dontwarn com.xuie.androiddemo.ui.** -keep class com.xuie.androiddemo.ui.** { *; } -keep class com.xuie.androiddemo.fragment.** { *; } -keep class com.xuie.androiddemo.adapter.** { *; } -keep class com.xuie.androiddemo.view.EnergyColumn -dontwarn butterknife.** -keep class butterknife.** { *; } -dontwarn com.dd.** -keep class com.dd.** { *; } -dontwarn android.** -keep class android.** { *; } -dontwarn com.android.** -keep class com.android.** { *; } -dontwarn com.squareup.** -keep class com.squareup.** { *; } -dontwarn jp.wasabeef.** -keep class jp.wasabeef.** { *; } -dontwarn rx.** -keep class rx.** { *; } ##################################### ########### 不优化泛型和反射 ########## ##################################### -keepattributes Signature
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 -keep public class * extends android .app .Activity 【不进行混淆类名的类,保持其原类名和包名】 -keep public abstract interface com .asqw .android .Listener {public protected <methods>; 【所有public protected 的方法名不进行混淆】} -keep public class com .asqw .android { public void Start (java.lang.String) ; 【对该方法不进行混淆】} -keepclasseswithmembernames class * { 【对所有类的native 方法名不进行混淆】 native <methods>;} -keepclasseswithmembers class * { 【对所有类的指定方法的方法名不进行混淆】 public <init>(android.content.Context, android.util.AttributeSet);} -keepclassmembers class * extends android .app .Activity {【对所有类的指定方法的方法名不进行混淆】 public void *(android.view.View);} -keepclassmembers enum * {【对枚举类型enum 的所有类的以下指定方法的方法名不进行混淆】 public static **[] values();public static ** valueOf(java.lang.String);} -keep class * implements android .os .Parcelable {【对实现了Parcelable接口的所有类的类名不进行混淆,对其成员变量为Parcelable$Creator类型的成员变量的变量名不进行混淆】 public static final android.os.Parcelable$Creator *;} -keepclasseswithmembers class org .jboss .netty .util .internal .LinkedTransferQueue {【对指定类的指定变量的变量名不进行混淆】 volatile transient org.jboss.netty.util.internal.LinkedTransferQueue$Node head; volatile transient org.jboss.netty.util.internal.LinkedTransferQueue$Node tail; volatile transient int sweepVotes; } -keep public class com .unionpay .** {*; }【对com.unionpay包下所有的类都不进行混淆,即不混淆类名,也不混淆方法名和变量名】
参考 http://frank-zhu.github.io/android/2015/10/28/android-build-config/ http://www.jayfeng.com/2015/11/07/Android%E6%89%93%E5%8C%85%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/