Android Studio 多渠道打包

什麼是Gradle 

Gradle是一種依賴管理工具,基於Groovy語言,面向Java應用爲主,它拋棄了基於XML的各類繁瑣配置,取而代之的是一種基於Groovy的領域特定(DSL)語言。Android Studio中新建項目成功後自動下載Gradle。 Gradle有幾個基本組件:html

1.整個項目的gradle配置文件build.gradlejava

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

內容主要包含了兩個方面:一個是聲明倉庫的源,我這裏用的是mavenCentral(), jcenter能夠理解成是一個新的中央遠程倉庫,兼容maven中心倉庫,並且性能更優。另外一個是聲明瞭android gradle plugin的版本,android studio 1.5.0正式版必需要求支持gradle plugin 1.5.0的版本。android


2.app文件夾下這個Module的gradle配置文件,也能夠算是整個項目最主要的gradle配置文件算法

apply plugin: 'com.android.application'

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

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    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’, 若是仍是之前的寫法,請改正過來。apache

  • buildToolsVersion這個須要你本地安裝該版本才行,不少人導入新的第三方庫,失敗的緣由之一是build version的版本不對,這個能夠手動更改爲你本地已有的版本或者打開 SDK Manager 去下載對應版本。app

  • applicationId表明應用的包名,也是最新的寫法,這裏就不在多說了。maven

  • android 5.0開始默認安裝jdk1.7才能編譯
  • minifyEnabled(混淆)也是最新的語法,很早以前是runProguard,這個也須要更新下。ide

  • 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 這個文件的內容:性能

#Wed Oct 21 11:34:03 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip

能夠看到裏面聲明瞭gradle的目錄與下載路徑以及當前項目使用的gradle版本,這些默認的路徑咱們通常不會更改的,這個文件裏指明的gradle版本不對也是不少導包不成功的緣由之一


4.settings.gradle

這個文件是全局的項目配置文件,裏面主要聲明一些須要加入gradle的module

include ':app'

文件中app是項目的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.** { *; }

 

http://www.cnblogs.com/ct2011/p/4152323.html
相關文章
相關標籤/搜索