Android Studio多渠道打包和代码混淆教程

发表于 5年以前  | 总阅读数:1664 次

什么是Gradle

Gradle是一种依赖管理工具,基于Groovy语言,面向Java应用为主,它抛弃了基于XML的各种繁琐配置,取而代之的是一种基于Groovy的领域特定(DSL)语言。Android Studio中新建项目成功后自动下载Gradle。
Gradle有几个基本组件:

1.整个项目的gradle配置文件build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.  

    buildscript {  
     repositories {  
            mavenCentral()  
        }  
        dependencies {  
            classpath 'com.android.tools.build:gradle:1.1.0'  

        // NOTE: Do not place your application dependencies here; they belong  
        // in the individual module build.gradle files  
        }  
    }  

    allprojects {  
        repositories {  
            mavenCentral()  
        }  
    }  

内容主要包含了两个方面:一个是声明仓库的源,我这里用的是mavenCentral(), jcenter可以理解成是一个新的中央远程仓库,兼容maven中心仓库,而且性能更优。另一个是声明了android gradle plugin的版本,android studio 1.1正式版必须要求支持gradle plugin 1.1的版本。


2.app文件夹下这个Module的gradle配置文件,也可以算是整个项目最主要的gradle配置文件

apply plugin: 'com.android.application'  

    buildscript {  
        repositories {  
            mavenCentral()  
        }  
        dependencies {  
            classpath 'com.android.tools.build:gradle:1.1.0'  

        }  
    }  

    android {  
        compileSdkVersion 17  
        buildToolsVersion "21.1.2"  

        defaultConfig {  
            applicationId "com.lippi.recorder"  
            minSdkVersion 15  
            targetSdkVersion 17  
            versionCode 1  
            versionName '1.4'  

            // dex突破65535的限制  
            multiDexEnabled true  
            // AndroidManifest.xml 里面UMENG_CHANNEL的value为 ${UMENG_CHANNEL_VALUE}  
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "channel_name"]  
        }  

        sourceSets {  
            main {  
                manifest.srcFile 'src/main/AndroidManifest.xml'  
                java.srcDirs = ['src/main/java']  
                resources.srcDirs = ['src/main/resources']  
                aidl.srcDirs = ['src/main/aidl']  
                renderscript.srcDirs = ['src/maom']  
                res.srcDirs = ['src/main/res']  
                assets.srcDirs = ['src/main/assets']  
                jniLibs.srcDir 'src/main/jniLibs'  
            }  

            // 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')  
        }  
        //执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。  
        lintOptions {  
            abortOnError false  
        }  

        //签名  
        signingConfigs {  
            debug {  
                storeFile file("/home/lippi/.android/debug.keystore")  
            }  
            relealse {  
                //这样写就得把demo.jk文件放在项目目录  
                storeFile file("recorder.jks")  
                storePassword "recorder"  
                keyAlias "recorder"  
                keyPassword "recorder"  
            }  
        }  

        buildTypes {  
            debug {  
                // 显示Log  
                buildConfigField "boolean", "LOG_DEBUG", "true"  

                versionNameSuffix "-debug"  
                minifyEnabled false  
                zipAlignEnabled false  
                shrinkResources false  
                signingConfig signingConfigs.debug  
            }  

            release {  
                // 不显示Log  
                buildConfigField "boolean", "LOG_DEBUG", "false"  
                //混淆  
                minifyEnabled true  
                //Zipalign优化  
                zipAlignEnabled true  

                // 移除无用的resource文件  
                shrinkResources true  
                //前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明  
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'  
                //签名  
                signingConfig signingConfigs.relealse  
            }  
        }  
        //渠道Flavors,配置不同风格的app  
        productFlavors {  
            GooglePlay {}  
            xiaomi {}  
            umeng {}  
            _360 {}  
            baidu {}  
            wandoujia {}  
        }  
        //批量配置  
        productFlavors.all { flavor ->  
            flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]  
        }  

        compileOptions {  
            sourceCompatibility JavaVersion.VERSION_1_7  
            targetCompatibility JavaVersion.VERSION_1_7  
        }  
        applicationVariants.all { variant ->  
            variant.outputs.each { output ->  
                def outputFile = output.outputFile  
                if (outputFile != null && outputFile.name.endsWith('.apk')) {  
                    def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}.apk")  
                    output.outputFile = new File(outputFile.parent, fileName)  
                }  
            }  
        }  

        dependencies {  
            compile fileTree(include: ['*.jar'], dir: 'libs')  
            compile 'org.apache.commons:commons-math:2.1'  
            compile 'org.slf4j:slf4j-log4j12:1.7.5'  
        }  
    }  
  • 文件开头apply plugin是最新gradle版本的写法,以前的写法是apply plugin: 'android', 如果还是以前的写法,请改正过来。

  • buildToolsVersion这个需要你本地安装该版本才行,很多人导入新的第三方库,失败的原因之一是build version的版本不对,这个可以手动更改成你本地已有的版本或者打开 SDK Manager 去下载对应版本。

  • applicationId代表应用的包名,也是最新的写法,这里就不在多说了。

  • android 5.0开始默认安装jdk1.7才能编译

  • minifyEnabled(混淆)也是最新的语法,很早之前是runProguard,这个也需要更新下。

  • proguardFiles这部分有两段,前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,免去了我们很多事,这个文件的目录在 /tools/proguard/proguard-android.txt , 后一部分是我们项目里的自定义的混淆文件,目录就在 app/proguard-rules.txt , 如果你用Studio 1.0创建的新项目默认生成的文件名是 proguard-rules.pro , 这个名字没关系,在这个文件里你可以声明一些第三方依赖的一些混淆规则,后面会具体讲到。

compile project(':extras:ShimmerAndroid')这一行是因为项目中存在其他Module,你可以理解成Android Library,由于Gradle的普及以及远程仓库的完善,这种依赖渐渐的会变得非常不常见,但是你需要知道有这种依赖的。


3.gradle目录下有个 wrapper 文件夹,里面可以看到有两个文件,我们主要看下 gradle-wrapper.properties 这个文件的内容:

#Fri Dec 19 21:59:01 CST 2014  
    distributionBase=GRADLE_USER_HOME  
    distributionPath=wrapper/dists  
    zipStoreBase=GRADLE_USER_HOME  
    zipStorePath=wrapper/dists  
    distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip  

可以看到里面声明了gradle的目录与下载路径以及当前项目使用的gradle版本,这些默认的路径我们一般不会更改的,这个文件里指明的gradle版本不对也是很多导包不成功的原因之一


4.settings.gradle

这个文件是全局的项目配置文件,里面主要声明一些需要加入gradle的module

include &apos;:recorder&apos;

文件中recorder是项目的module,如果还有其他module按照相同的格式加上去。


Gradle多渠道打包

由于国内Android市场众多渠道,为了统计每个渠道的下载及其它数据统计,就需要我们针对每个渠道单独打包,如果让你打几十个市场的包岂不烦死了,不过有了Gradle,这再也不是事了。
以友盟统计为例,在AndroidManifest.xml里面会有这么一段:

<meta-data  
    android:name="UMENG_CHANNEL"  
    android:value="Channel_ID" />  

里面的Channel_ID就是渠道标示。我们的目标就是在编译的时候这个值能够自动变化。

  • 第一步 在AndroidManifest.xml里配置PlaceHolder
<meta-data  
    android:name="UMENG_CHANNEL"  
    android:value="${UMENG_CHANNEL_VALUE}" />  
  • 第二步 在build.gradle 设置productFlavors
android {   
    productFlavors {  
        xiaomi {}  
        _360 {}  
        baidu {}  
        wandoujia {}  
    }   

    productFlavors.all {   
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]   
        }  
    }  

然后直接执行./gradlew assembleRelease然后就等待打包完成吧。

assemble 这个命令,会结合 Build Type 创建自己的task,如:

  • ./gradlew assembleDebug

  • ./gradlew assembleRelease

除此之外 assemble 还能和 Product Flavor 结合创建新的任务,其实 assemble 是和 Build Variants 一起结合使用的,而 Build Variants = Build Type + Product Flavor , 举个例子大家就明白了:

如果我们想打包wandoujia渠道的release版本,执行如下命令就好了:

./gradlew assembleWandoujiaRelease

如果我们只打wandoujia渠道版本,则:

./gradlew assembleWandoujia

此命令会生成wandoujia渠道的Release和Debug版本

同理我想打全部Release版本:

./gradlew assembleRelease

这条命令会把Product Flavor下的所有渠道的Release版本都打出来。


代码混淆

下面是常见的的proguard.cfg配置项:

# 指定代码的压缩级别
    -optimizationpasses 5

    # 包明不混合大小写
    -dontusemixedcaseclassnames

    # 不去忽略非公共的库类
    -dontskipnonpubliclibraryclasses

     # 优化不优化输入的类文件
    -dontoptimize

     # 预校验
    -dontpreverify

     # 混淆时是否记录日志
    -verbose

     # 混淆时所采用的算法
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

    # 保护注解
    -keepattributes *Annotation*

    # 保持哪些类不被混淆
    -keep public class * extends android.app.Fragment
    -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
    # 如果有引用v4包可以添加下面这行
    -keep public class * extends android.support.v4.app.Fragment



    # 忽略警告
    -ignorewarning

    #记录生成的日志数据,gradle build时在本项目根目录输出 

    # apk 包内所有 class 的内部结构
    -dump class_files.txt
    # 未混淆的类和成员
    -printseeds seeds.txt
    # 列出从 apk 中删除的代码
    -printusage unused.txt
    # 混淆前后的映射
    -printmapping mapping.txt

    #记录生成的日志数据,gradle build时 在本项目根目录输出-end


    #####混淆保护自己项目的部分代码以及引用的第三方jar包library

    #-libraryjars libs/umeng-analytics-v5.2.4.jar

    #三星应用市场需要添加:sdk-v1.0.0.jar,look-v1.0.1.jar
    #-libraryjars libs/sdk-v1.0.0.jar
    #-libraryjars libs/look-v1.0.1.jar

    #如果不想混淆 keep 掉
    -keep class com.lippi.recorder.iirfilterdesigner.** {*; }
    #友盟
    -keep class com.umeng.**{*;}
    #项目特殊处理代码

    #忽略警告
    -dontwarn com.lippi.recorder.utils**
    #保留一个完整的包
    -keep class com.lippi.recorder.utils.** {
        *;
     }

    -keep class  com.lippi.recorder.utils.AudioRecorder{*;}


    #如果引用了v4或者v7包
    -dontwarn android.support.**

    #混淆保护自己项目的部分代码以及引用的第三方jar包library-end

    -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*(...);
    }

    #保持 native 方法不被混淆
    -keepclasseswithmembernames class * {
        native <methods>;
    }

    #保持自定义控件类不被混淆
    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet);
    }

    #保持自定义控件类不被混淆
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }

    #保持 Parcelable 不被混淆
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }

    #保持 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;
        !static !transient <fields>;
        !private <fields>;
        !private <methods>;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }

    #保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
    #-keepclassmembers enum * {
    #  public static **[] values();
    #  public static ** valueOf(java.lang.String);
    #

    -keepclassmembers class * {
        public void *ButtonClicked(android.view.View);
    }

    #不混淆资源类
    -keepclassmembers class **.R$* {
        public static <fields>;
    }

    #避免混淆泛型 如果混淆报错建议关掉
    #-keepattributes Signature

    #移除log 测试了下没有用还是建议自己定义一个开关控制是否输出日志
    #-assumenosideeffects class android.util.Log {
    #    public static boolean isLoggable(java.lang.String, int);
    #    public static int v(...);
    #    public static int i(...);
    #    public static int w(...);
    #    public static int d(...);
    #    public static int e(...);
    #

    #如果用用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错。
    #gson
    #-libraryjars libs/gson-2.2.2.jar
    -keepattributes Signature
    # Gson specific classes
    -keep class sun.misc.Unsafe { *; }
    # Application classes that will be serialized/deserialized over Gson
    -keep class com.google.gson.examples.android.model.** { *; }

参考文献:Android Tools Project Site

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:7月以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:7月以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:7月以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:7月以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:7月以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:7月以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:7月以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:7月以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:7月以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:7月以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:7月以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:7月以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:7月以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:7月以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:7月以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:7月以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:7月以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:7月以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  236875次阅读
vscode超好用的代码书签插件Bookmarks 1年以前  |  6888次阅读
 目录