安卓 代码混淆与打包

风流不在谈锋胜,袖手无言味最长。这篇文章主要讲述安卓 代码混淆与打包相关的知识,希望能为你提供帮助。
代码混淆部分
gradle的配置

安卓 代码混淆与打包

文章图片

minifyEnabled true proguardFiles getDefaultProguardFile(\'proguard-android.txt\'), \'proguard-rules.txt\'

proguard-rules.pro混淆配置
###-----------基本配置-不能被混淆的------------ -keep public class * extends android.app.Activity -keep public class * extends android.app.Fragment -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference#support.v4/v7包不混淆 -keep class android.support.** { *; } -keep class android.support.v4.** { *; } -keep public class * extends android.support.v4.** -keep interface android.support.v4.app.** { *; } -keep class android.support.v7.** { *; } -keep public class * extends android.support.v7.** -keep interface android.support.v7.app.** { *; } -dontwarn android.support.**# 忽略警告#保持注解继承类不混淆 -keep class * extends java.lang.annotation.Annotation {*; } #保持Serializable实现类不被混淆 -keepnames class * implements java.io.Serializable #保持Serializable不被混淆并且enum 类也不被混淆 -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } #保持枚举enum类不被混淆 -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } #自定义组件不被混淆 -keep public class * extends android.view.View { public < init> (android.content.Context); public < init> (android.content.Context, android.util.AttributeSet); public < init> (android.content.Context, android.util.AttributeSet, int); public void set*(...); }#不混淆资源类 -keepclassmembers class **.R$* { public static < fields> ; }###-----------第三方jar包library混淆配置------------ #ormlite混淆配置 #-libraryjars libs/ormlite-android-5.0.jar #-libraryjars libs/ormlite-core-5.0.jar -dontwarn com.j256.ormlite.** -keep class com.j256.ormlite.** { *; } -keep class com.envy15.cherry.base.orm.** { *; } #json-lib混淆配置 #-libraryjars libs/json-lib-2.4-jdk15.jar -dontwarn net.sf.json.** -keep class net.sf.json.** { *; } #json-lib关联包 #-libraryjars libs/commons-beanutils-1.8.3.jar -dontwarn org.apache.commons.** -keep class org.apache.commons.** { *; } #universalimageloader图片加载框架不混淆 -keep class com.nostra13.universalimageloader.** { *; } -dontwarn com.nostra13.universalimageloader.** #Gson相关的不混淆配置 -keepattributes Signature -keepattributes *Annotation* -keep class com.google.gson.** { *; } -dontwarn com.google.gson.** -keep class com.envy15.cherry.fragment.crossover.model.** { *; } -dontwarn com.envy15.cherry.fragment.crossover.model.** -keep class com.envy15.cherry.fragment.discover.model.** { *; } -dontwarn com.envy15.cherry.fragment.discover.model.** -keep class com.envy15.cherry.fragment.local.model.** { *; } -dontwarn com.envy15.cherry.fragment.local.model.** -keep class com.envy15.cherry.fragment.setting.model.** { *; } -dontwarn com.envy15.cherry.fragment.setting.model.** #prt-lib下拉刷新框架不混淆 -keep class in.srain.cube.views.ptr.** { *; } -dontwarn in.srain.cube.views.ptr.** #PullToRefreshLibrary下拉刷新框架不混淆 -keep class com.handmark.pulltorefresh.library.** { *; } -dontwarn com.handmark.pulltorefresh.library.**#参考: #http://blog.csdn.net/zuiwuyuan/article/details/48552701 #http://blog.csdn.net/fengyuzhengfan/article/details/43876197 #http://blog.isming.me/2014/05/31/use-proguard/ #http://hanhailong.com/2015/12/28/Android%E8%BF%9B%E9%98%B6%E4%B9%8BProGuard%E4%BB%A3%E7%A0%81%E6%B7%B7%E6%B7%86/ # 关于混淆的思考: #https://www.zhihu.com/question/37446729 # 扩展:资源文件混淆 #http://blog.csdn.net/Fancy_xty/article/details/51202866 #代码混淆规则 # 指定代码的压缩级别 #-optimizationpasses 5 # 是否使用大小写混合 #-dontusemixedcaseclassnames # 是否混淆第三方jar #-dontskipnonpubliclibraryclasses # 混淆时是否做预校验 #-dontpreverify # 混淆时是否记录日志 #-verbose # 混淆时所采用的算法 #-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*#-keep public class * extends android.app.Activity# 保持哪些类不被混淆 #-keep public class * extends android.app.Application# 保持哪些类不被混淆 #-keep public class * extends android.app.Service# 保持哪些类不被混淆 #-keep public class * extends android.content.BroadcastReceiver# 保持哪些类不被混淆 #-keep public class * extends android.content.ContentProvider# 保持哪些类不被混淆 #-keep public class * extends android.app.backup.BackupAgentHelper# 保持哪些类不被混淆 #-keep public class * extends android.preference.Preference# 保持哪些类不被混淆 #-keep public class com.android.vending.licensing.ILicensingService# 保持哪些类不被混淆#-keepclasseswithmembernames class * {# 保持 native 方法不被混淆 #native < methods> ; #} # #-keepclasseswithmembers class * {# 保持自定义控件类不被混淆 #public < init> (android.content.Context, android.util.AttributeSet); #} # #-keepclasseswithmembers class * { #public < init> (android.content.Context, android.util.AttributeSet, int); # 保持自定义控件类不被混淆 #} # #-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 不被混淆 #public static final android.os.Parcelable$Creator *; #}#-keep class MyClass; # 保持自己定义的类不被混淆

 
打包发布部分
S1.使用默认方式打包签名APK
AndroidStudio选择Build => Generate Signed APK
总体步骤流程如下:
安卓 代码混淆与打包

文章图片

详细操作步骤:
安卓 代码混淆与打包

文章图片

S2. 多渠道打包APK
属性配置
productFlavors
      productFlavors {
              aVer {
                      resValue("string","strKey","myKey")
                      applicationId "com.simple.pkg.debug"
              }
              bVer {
                      applicationId "com.simple.pkg.beta"
              }
              cVer {
                      applicationId "com.simple.pkg.res"
              }
      }
signingConfigs
      signingConfigs {
              release {
                      storeFile file(\'E:/XXX/app.jks\') // 签名证书文件
                      storePassword \'you password\' // 证书密码
                      keyAlias \'test\'
                      keyPassword \'you password \'
              }
      }
buildTypes
      buildTypes {
              mbeta {
                      signingConfig android.signingConfigs.release
                      minifyEnabled false
              }
      }
 
S3.gradle打包自动化-定制apk文件名
gradle属性及变量定义的几种方式
变量定义
方式1(for gradle)
工程目录下gradle.properties定义属性:appName = MyAppName
App目录下build.gradle读取自定义属性:project.appName
方式2(for java)
App目录下build.gradle定义属性:
      productFlavors {
              aVer {
                      // gradle定义全局变量方式2-代码使用
                      buildConfigField "int", "varInt", "0"
                      buildConfigField "String", "varString", \'"abc"\'
              }
}
Java代码读取属性:BuildConfig.varInt; BuildConfig.varString;
方式3(for java)
App目录下build.gradle定义属性:
      productFlavors {
              aVer {
                      resValue("string","strKey","myKey")
              }
}
ava代码读取属性:context.getString(R.string.strKey);
方式4
App目录下build.gradle定义属性:
def flavorName = "undefine"
def indexFlavor(String str) {
      return str.substring(0,str.length())
}
方式5
App目录AndroidManifest.xml定义变量
              < meta-data
                      android:name="env_key0"
                      android:value="https://www.songbingjia.com/android/${env_val0}" />
build.gradle修改env_val0
      buildTypes {
              debug {
                      minifyEnabled false
                      manifestPlaceholders = [env_val0: "VAL0", env_val1: "VAL1"]
              }
      }
Java代码中获取meta属性定义
      public static String getMetaValue(Context context,String key){
              ApplicationInfo applicationInfo = null;
              try {
                      applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
              } catch (PackageManager.NameNotFoundException e) {
                      e.printStackTrace();
              }
              if (applicationInfo == null){
                      return "";
              }
              return applicationInfo.metaData.getString(key);
      }
 
Ref:
        android studio gradle 多版本多apk打包(打包系列教程之五)
        Gradle 自定义构建全局变量
        android studio 自定义gradle变量
 
定制apk文件名
变量定义
自定义生成APK文件名
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
                // appName + version + createTime + svnVersion + flavor + buildType
                def fileName = "fileName.apk"
                output.outputFile = new File(outputFile.parent, fileName)
            }
      }
获取相关属性
AppName:自定义方式或getName()
Version:版本, defaultConfig.versionName
CreateTime:创建时间,new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
SvnVersion :SVN提交版本号
Flavor :编译渠道版本
BuildType:debug/beta/release版本
def fileName = "${project.appName}_v${defaultConfig.versionName}_${releaseTime()}_" +
                                                      "s${getSvnRevision()}_${indexFlavor(productFlavors.name)}_${getName()}.apk"
 
 
Ref:
        Android Gradle实用技巧——APK文件名中加上SVN版本号,日期等
        Android 使用Gradle打包APP名称和版本号
 
参考问题:
        buildTypes中加上signingConfig sigingConfigs.release运行就报错
build.gradle多渠道打包完整示例
// app/build.gradle文件 import org.tmatesoft.svn.core.wc.* // for svn version apply plugin: \'com.android.application\' def releaseTime() { return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) } def indexFlavor(String str) { return str.substring(0,str.length()) } def getSvnRevision() { // for svn ISVNOptions options = SVNWCUtil.createDefaultOptions(true); SVNClientManager clientManager = SVNClientManager.newInstance(options); SVNStatusClient statusClient = clientManager.getStatusClient(); SVNStatus status = statusClient.doStatus(projectDir, false); SVNRevision revision = status.getCommittedRevision(); return revision.getNumber(); } android { signingConfigs { } compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.simple.res" minSdkVersion 15 targetSdkVersion 21 versionCode 1 versionName "1.0" multiDexEnabled true// dex突破65535的限制 } productFlavors { aVer { // gradle定义全局变量方式2-代码使用 buildConfigField "int", "varInt", "0" buildConfigField "String", "varString", \'"abc"\' // resValue("string","strKey","myKey") applicationId "com.simple.res.debug" } bVer { applicationId "com.simple.res.beta" } } signingConfigs { release { storeFile file(\'E:/XXX/App.jks\') storePassword \'you password\' keyAlias \'TEST\' keyPassword \'you password\' } } buildTypes { debug { minifyEnabled false } mbeta { signingConfig android.signingConfigs.release minifyEnabled false } release { signingConfig android.signingConfigs.release proguardFiles getDefaultProguardFile(\'proguard-android.txt\'), \'proguard-rules.pro\' minifyEnabled true shrinkResources true // 指定APK文件名 applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile // appName + version + createTime + svnVersion + flavor + buildType def fileName = "${project.appName}_v${defaultConfig.versionName}_${releaseTime()}_" + "s${getSvnRevision()}_${indexFlavor(productFlavors.name)}_${getName()}.apk" output.outputFile = new File(outputFile.parent, fileName) } } } } } // project/build.gradle文件 // 添加classpath group: \'org.tmatesoft.svnkit\', name: \'svnkit\', version: \'1.8.11\'支持获取// SVN提交版本号 buildscript { repositories { jcenter() } dependencies { classpath \'com.android.tools.build:gradle:2.2.3\' classpath group: \'org.tmatesoft.svnkit\', name: \'svnkit\', version: \'1.8.11\' } // project/build.gradle文件 appName = NewApp

 
* 崩溃日志记录 * 参考: *http://blog.csdn.net/u012333411/artile/details/49019415 *http://blog.csdn.net/wangyuexing_blog/article/details/39009069


【安卓 代码混淆与打包】

    推荐阅读