gradle批量打包Android apk:不同的包使用不同的icon、label

前几天学习了使用gradle批量打包apk、加签名及混淆等方法,现在开始学习怎么给每个包替换不同的icon、label或其他属性。

参考资料:http://stackoverflow.com/questions/25981156/toolsreplace-not-replacing-in-android-manifest

                  http://blog.csdn.net/maosidiaoxian/article/details/42671999

                  http://zhidao.baidu.com/link?url=k6epEW6_POVCf88EsosZz2LCyodSbglsdWLujEfXln5CapaLMWntPQq2RyDl0R-wKcGfwaM7gT6o38-ravkmqFITjjhRkPN7ufxKfS4Ddcu

 

替换icon、label的原理是Android的"manifest merger",大家可以先从http://blog.csdn.net/maosidiaoxian/article/details/42671999上了解一下"manifest merger"的原理和详细规则。

下面开始讲我的具体实现步骤(我下面讲的步骤以前面几篇博客为基础,单独看的话可能有点突兀,可以从前面几篇博客顺序看下来):

一、配置manifest和gradle.build

1.首先将useOldManifestMerger配置为false,不使用原始的manifest。如下:

productFlavors { 
        useOldManifestMerger false

        …… 
 }

 批量打包的时候如果不需要改动manifest中的属性,可以设useOldManifestMerger设为true,在gradle.build中配置相应的包名,如:

productFlavors { 
        useOldManifestMerger true
        
  app1{ 
         //这里可以配置不同的包名 
         applicationId="com.example.erase1"
  } 
  app2{ 
      applicationId="com.example.erase2"
  } 
 }

2.将原始manifest中的内容copy到为每个包单独配置的manifest中去,在这里分别命名为:AndroidManifest1.xml、AndroidManifest2.xml。

   a.删除AndroidManifest*.xml中配置包名的代码,因为已经在gradle.build中配置过了,不能重复配置。否则,build的时候回提示如下error:

Execution failed for task ':processApp1DebugManifest'.
> Manifest merger failed : Overlay manifest:package attribute declared at AndroidManifest1.xml:4:5 value=(com.example.erase1)
        has a different value=(com.example.erase) declared in main manifest at AndroidManifest.xml:3:5
        Suggestion : remove the overlay declaration at AndroidManifest1.xml     and place it in the build.gradle:
                flavorName {
                        applicationId = "com.example.erase1"
                }

   b.为了解决多个manifest中相同activity重复注册的问题,在gradle.build中增加以下代码:

lintOptions {
      checkReleaseBuilds false
      // Or, if you prefer, you can continue to check for errors in release builds,
      // but continue the build even when errors are found:
      abortOnError false
  }

如果gradle.build里没有这一项,build时会给出error提示:

F:\eclipse-SDK-3.7-win32\workapace\Erase\tests\AndroidManifest2.xml:18: Error: Duplicate registration for activity com.example.erase.MainActivity [Dup
licateActivity]
            android:name="com.example.erase.MainActivity"
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   Explanation for issues of type "DuplicateActivity":
   An activity should only be registered once in the manifest. If it is
   accidentally registered more than once, then subtle errors can occur, since
   attribute declarations from the two elements are not merged, so you may
   accidentally remove previous declarations.

1 errors, 0 warnings
                                                                                                                                                     W
rote HTML report to file:/F:/eclipse-SDK-3.7-win32/workapace/Erase/build/outputs/lint-results-app2Release-fatal.html
Wrote XML report to F:\eclipse-SDK-3.7-win32\workapace\Erase\build\outputs\lint-results-app2Release-fatal.xml
:lintVitalApp2Release FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':lintVitalApp2Release'.
> Lint found fatal errors while assembling a release target.

To proceed, either fix the issues identified by lint, or modify your build script as follows:
...
android {
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}
...

三、修改android:icon、android:label等属性

通过以上操作,manifest和gradle.build中基本的配置就完成了,接下来修改关键属性android:icon、android:label。

1.将AndroidManifest*.xml中android:icon、android:label属性配置成不同的值,这属于属性的重定义,需要在manifest中增加tools:replace,代码实例如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:versionCode="100002"
    android:versionName="1.00.002" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:label="@string/palette"
        android:icon="@drawable/ic_launcher2"
        tools:replace="android:label,android:icon"
        android:theme="@style/AppTheme" >

否则,build error会给出以下提示,gradle的error提示还是比较智能的,按照提示中给出的方法就可以解决问题。

:processApp1DebugManifest
F:\eclipse-SDK-3.7-win32\workapace\Erase\tests\AndroidManifest1.xml:13:9 Error:
        Attribute application@icon value=(@drawable/ic_launcher1) from AndroidManifest1.xml:13:9
        is also present at AndroidManifest.xml:13:9 value=(@drawable/ic_launcher)
        Suggestion: add 'tools:replace="android:icon"' to <application> element at AndroidManifest1.xml:11:5 to override

 

按照以上步骤一步步操作,最后在cmd工程目录下执行gradle clean、gradle build,build成功后,将apk安装到手机上运行,你会发现不同包名的应用图标都已经更换了,但是应用名称还都是一样的,这是因为:

桌面上显示的程序名字默认是程序launcher activity的label。

只改了applicantion的label,但是没有修改launcher activity的label,就会出现应用名称无法修改的表象,这是笔者追查了好久才查不来的,当然也说明了笔者Android基础不扎实。呵呵~

配置好的manifest和build.gradle代码如下:

build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.12.+'
    }
}
apply plugin: 'android'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
}

android {
    compileSdkVersion 17
    buildToolsVersion "22.0.1"

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

        // 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')
       
        app1{ 
         manifest.srcFile 'tests/AndroidManifest1.xml' 
     } 
     app2{ 
         manifest.srcFile 'tests/AndroidManifest2.xml' 
     } 
        instrumentTest.setRoot('tests') 
    }
   
    productFlavors { 
        useOldManifestMerger false
       
  app1{ 
         //这里可以配置不同的包名 
         applicationId="com.example.erase1"
  } 
  app2{ 
      applicationId="com.example.erase2"
  } 
 }
 
 //签名   
    signingConfigs {   
  myConfig {   
      storeFile file("../keystore")      //签名文件   
      storePassword "*****"       
      keyAlias "*****"                
      keyPassword "*****"  //签名密码   
  }
    }
   
    buildTypes{
     release {
      signingConfig  signingConfigs.myConfig
      //混淆
      runProguard true
      proguardFile '../../android-sdks/andrid-sdks/tools/proguard/proguard-android.txt'
      //混淆
     }
    }
   
     lintOptions {
      checkReleaseBuilds false
      // Or, if you prefer, you can continue to check for errors in release builds,
      // but continue the build even when errors are found:
      abortOnError false
  }

}

AndroidManifest*.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:versionCode="100002"
    android:versionName="1.00.002" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher1"
        android:label="@string/erase"
        tools:replace="android:icon,android:label"
        android:theme="@style/AppTheme" >
        <activity
            tools:replace="android:label"
            android:name="com.example.erase.MainActivity"
            android:label="@string/erase" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2.至于怎么查看当前应用显示的名称不是应用真是名称呢?卸载应用就可以了:长按应用图标,将应用拖到“卸载”区,界面上会提示“***Activity属于以下应用:***”。

 

至此,我们就完成了利用gradle批量打包,并更改应用图标、名称的功能。最总的学习目标是:如何使用同一套代码打包出不同功能、不同UI的apk,这中间肯定有很多苦难需要各个击破,一步步学习吧~

 

你可能感兴趣的:(android,gradle,标签,经验)