多渠道打包,生成不同包名的包

来对多渠道打包,并生成不同的包名的知识点做个总结。需要生成不同包名的原因是为了运营的ASO。

方法:

1.直接建立渠道的文件夹,修改Manifest里面的包名
2.利用占位符

当然上面两种方法各有优劣,最后说一下他们的各自的一些特点。

首先来说第一种方法,步骤:

1.根据需要生成多少个包名的包建立和main同级的文件夹。

例如:我这里需要两个不同包名的包,那就需要建立两个不同渠道的文件夹。
渠道文件夹

2.在文件夹里面新建Maifest文件

因为包名是在Manifest文件里面定义的,所以需要建立Manifest文件,当然这个Manifest文件里面拷贝过来,你可能会觉得太麻烦,我只是替换一个包名需要把整个Manifest都拷贝过来么,这也太坑了,其实没有这么严重,包名一般包括在用户手机桌面上面显示的名字,和你去应用程序管理器里面看到的名字,这两个名字是可以不同的。

在应用程序管理器里面显示的名字是由application节点的android:label属性决定的。
应用程序的名字

用户手机桌面上面显示的名字是由应用程序的第一个Activity的android:label决定的,如果第一个Activity没有指定label属性的话,就是使用的Application的android:label的名字。
桌面显示的名字
顺便提一句,应用程序的第一个Activity是有下面的intent-filter的Activity。

<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

这里我们明白了,应用程序的两个包名,那么既然我们需要改变的只是包名而已,就只需要把application节点和第一个Activity在Manifest里面的配置拷贝过来就可以了
所以这里需要的两个Manifest文件分别是这样的:
先贴一下main渠道的主的Manifest文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.name.replace"
xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        ...
        其他配置
        ...
    </application>
</manifest>

app_name_1渠道:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.name.replace"
xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name_1"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="android:label">
        <activity
            android:name=".MainActivity"
            android:label="@string/desk_name_1"
            tools:replace="android:label">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

app_name_2渠道:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.name.replace"
xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name_2"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="android:label">
        <activity
            android:name=".MainActivity"
            android:label="@string/desk_name_2"
            tools:replace="android:label">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

这里可以看到app_name_1里面的Manifest和app_name_2里面的Manifest并没有太大的差别,只是包名改了一下而已。这两个文件没有什么可比较的价值。

着重看一下app_name_2渠道的Manifest和main里面的Manifest的差别,如果你说没有差别,那就比较尴尬了,妈蛋,我450度的眼镜都看出差别了。

两个差别:
(1).在app_name_2的渠道里面引入了新的tools命名空间。

xmlns:tools=”http://schemas.android.com/tools”
并且在application节点和第一个Activity节点添加了tools:replace=”android:label”语句。
如果没有添加Gradle在使用Manifest Merger Tool进行合并Manifest的时候出出问题。

(2).app_name_2渠道除了application节点和第一个Activity节点之外,没有其他的东西。

不需要main里面的其他的一些四大组件相关的一些东西。

3.在build.gradle里面配置渠道信息
    productFlavors {
        app_name_1 {}
        app_name_2 {}
        app_main {}
        }

这里的渠道名要和一开始建立的文件夹的名字一样,如果不一样,打出的包就是main里面的包。

4.打包即可



第二种方法,步骤:

得益于gradle对于占位符的支持,第二种方法远没有第一种方法那么麻烦。
关于占位符的用法有很多,比如可以动态的定义Activity的名字,Service的名字等。详细的可以自行Google。
关于gradle的清单合并可以看这一篇翻译的文章,讲解的非常详细:
清单合并:http://blog.csdn.net/maosidiaoxian/article/details/42671999

1.在Manifest里面配置占位符

由于不需要建立文件夹,这里说的Manifest就是main里面的Manifest。
当属性值包含一个占位符时,合并工具将把此占位符的值换成一个注入的值。注入的值是在build.gradle里面定义的。
占位符值的语法是 ${name},因为@符号已经预留给了链接。在最后的文件合并发生之后,并且生成合并后的 android 的清单文件输出之前,带有占位符的所有值将都会被替换为注入的值。如果变量名是未知的,将导致构建失败。
Manifest文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.name.replace"
xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="${app_name}"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${umeng_channel}"/>
        <activity
            android:name=".MainActivity"
            android:label="${desk_name}">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

这里定义了三个占位符,app_name,desk_name,umeng_channel。
占位符可以替换的还有很多用处,想了解更多的可以自己查资料。

2.在build.gradle里面配置渠道信息

这里贴出整个Manifest文件,供大家更好的看清。

apply plugin: 'com.android.application'
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    defaultConfig {
        applicationId "com.name.replace"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        manifestPlaceholders = [
                app_name     : "@string/app_name",
                desk_name    : "@string/app_name",
                umeng_channel: "测试版"
        ]
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
//        app_name_1 {}
//        app_name_2 {}
//        app_main {}
        app_qq {
            manifestPlaceholders = [
                    app_name     : "@string/app_name_1",
                    desk_name    : "@string/desk_name_1",
                    umeng_channel: "应用宝"
            ]
        }
        app_pp {
            manifestPlaceholders = [
                    app_name     : "@string/app_name_2",
                    desk_name    : "@string/desk_name_2",
                    umeng_channel: "pp助手"
            ]
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
}

可以看到我们对Manifest里面定义的三个占位符做了替换。
这里我们既在defaultConfig里面定义了,又在不同的渠道里面做了再次定义,最后渠道里面的优先级会高。
其实如果一开始没有配置渠道信息,但是我们定义了占位符的话,是编译不过去的,必须在defaultConfig里面定义默认的一些属性。

3.打包即可

最开始的时候我们说了这两种方法各有优缺点,在以前的公司的时候采用的是第一种方案,原因有两点:
1.采用第一种方案,可以对每个渠道加上渠道的logo,比如360的渠道需要360的logo,百度的渠道需要百度的logo,那么采用第一种方法就很好实现了,把main里面的res/layout里面的启动界面拷贝一份到对应的渠道文件里面进行修改,替换logo。
第一种方法里面不止可以放置Manifest文件,还可以放置res目录。

2.当时的渠道包不需要我们技术人员去打,由运营去打,技术这边当时是开发了一个工具供运营那边打渠道包专用,技术这边只需要打好不同的包名的包即可。

所以第一种方法的优点是可以完成一些其余的特殊的操作,缺点是比较麻烦。第二种方法是实现比较简单,但是有些特殊的操作就不能行了。

Demo地址:http://download.csdn.net/detail/qy274770068/9498668

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Android 多渠道打包指的是在同一份代码基础上,生成不同渠道的 APK 文件,这些 APK 文件在安装后会显示不同的渠道信息。 下面是一种常见的多渠道打包方式: 1. 在 app 模块的 build.gradle 文件中添加以下代码: ``` android { // 省略其他配置项 flavorDimensions "channel" productFlavors { googlePlay { dimension "channel" // 配置 Google Play 版本的包名等信息 applicationId "com.example.app.google" // 省略其他配置项 } xiaomi { dimension "channel" // 配置小米版本的包名等信息 applicationId "com.example.app.xiaomi" // 省略其他配置项 } huawei { dimension "channel" // 配置华为版本的包名等信息 applicationId "com.example.app.huawei" // 省略其他配置项 } } } ``` 2. 在 gradle.properties 文件中添加以下代码: ``` CHANNELS=googlePlay,xiaomi,huawei ``` 3. 创建一个名为 channel.gradle 的文件,用于动态生成不同渠道的 APK 文件: ``` def getChannelName() { // 从 gradle.properties 文件中读取 CHANNELS 变量 def channels = rootProject.ext.CHANNELS.split(',') // 获取当前渠道的索引,注意这个值是根据 assemble 命令的参数确定的 def channelIndex = project.getProperties().get("channelIndex") // 返回当前渠道的名字 return channels[channelIndex.toInteger()] } android.applicationVariants.all { variant -> variant.outputs.all { // 修改 APK 文件名,添加渠道信息 outputFileName = "${variant.name}-${variant.versionName}-${getChannelName()}.apk" } } ``` 4. 执行以下命令生成不同渠道的 APK 文件: ``` ./gradlew assembleGooglePlay -PchannelIndex=0 ./gradlew assembleXiaomi -PchannelIndex=1 ./gradlew assembleHuawei -PchannelIndex=2 ``` 上述命令中的 assembleGooglePlay、assembleXiaomi、assembleHuawei 分别对应不同的 productFlavors,-PchannelIndex 参数用于指定当前渠道的索引。执行完这些命令后,会在 app/build/outputs/apk 目录下生成三个不同渠道的 APK 文件。 这是一种较为简单的多渠道打包方式,具体实现方式可能会因项目需求而有所不同

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值