AndroidStudio 多渠道打包实践总结

作者: 三少爷的码 | 来源:发表于2017-08-17 09:38 被阅读480次

    写在前面的话

    公司之前使用Ant打包的,一个包平均要10分钟,三四个包下来,一个小时过去了,作为一名有追求的程序员,这是不能忍受的,所以老大安排我对打包脚本进行改造。

    本次改造包括以下内容:

    1. 编译器由IDEA向AndroidStudio转换
    2. 增加多渠道打包
    3. 修改打包后的apk文件名
    4. 备份混淆后的mapping文件

    接下来就按照这几块来细说一下多渠道打包的事

    编译器由IDEA向AndroidStudio转换

    公司的项目原本是在IDEA上开发的,这款软件是后台开发的神器,AS在其基础上增加了一些新功能。编译的管理也不是Gradle,所以老大想转到AS开发,然后用Gradle。
    在转的过程中也遇到了一些问题。总结来说这些问题可以分为:分包,多个jar包重复引用,低版本Android support包缺少一些方法,uses-sdk的兼容问题。我把异常信息贴上来就行了,本文重点不在这里。

    多jar重复引用
    Error:Execution failed for task ':_2C:transformClassesWithJarMergingForRelease'.
    > com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: io/agora/rtc/IRtcEngineEventHandler$AudioVolumeInfo.class
    
    分包
    Error:Execution failed for task ':_2C:transformClassesWithDexForRelease'.
    > com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
    
    版本过低,缺少方法
    Error:(263, 22) 错误: 找不到符号
    符号:   方法 addDrawerListener(Main)
    位置: 类型为DrawerLayout的变量 mDrawerLayout
        
    将依赖的minSdkVersion改为与项目一致
    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="22"
        tools:overrideLibrary="org.ffmpeg.android,android.support.v7.recyclerview,android.support.coreui,
            android.support.compat,android.support.v4,android.support.fragment,android.support.mediacompat,
            android.support.coreutils,android.support.v13"/>
    

    增加多渠道打包

    除了要增加多渠道打包外,还需要在多渠道中修改一些东西,具体修改的内容如下:

    1、首先不同的应用需要修改applicationId(百度地图,友盟统计,讯飞语音的App_key)
    2、用到shareSDK,不同的渠道要替换现在assets这个目录下面的文件。
    3、不同的应用的图标替换 
    4、应用数据的SD卡存储目录 
    5、应用的AAS接口地址
    6、修改生成的apk名字和备份mapping 文件
    

    1 修改applicationId 。修改友盟,微信等第三方App_Key等动态数据都是通过 manifestPlaceholders 占位符的形式进行修改 贴一下图看一下就懂了

    不同的渠道有不同的applicationId,然后修改应用的名字,App_Key PERMISSION这个字段是由于项目中用到了自定义权限,所以要根据applicationId进行修改。到此,第一步完成了,是不是很快?

    2 用到shareSDK,不同的应用要替换现在assets这个目录下面的文件。

    3 不同的应用的图标替换

    处理这个问题实质就是资源文件的替换(包括assets 和res 文件的合并)

    多说无益,看图把

    这里我用了相对路径,相对于App项目,这样子提交到svn的话就不用修改路径了。通过为每一个渠道指定assets和res的目录达到编译的时候动态合并资源

    4 应用数据的SD卡存储目录

    5 应用的AAS接口地址

    这个项的要用到buildConfigField 和BuildConfig,在buildConfigField的参数会在编译的时候生成到BuildConfig中,每一个渠道都会生成一个BuildConfig,通过它来达到动态修改SD卡存储目录和AAS接口地址 。

    老规矩,上图

    这个是在build.gradle中定义的


    看看BuildConfig中的定义


    说完这个后我还想说一个,如何在这个BuildConfig中生成一个对象,

    解决这个问题的话就想想我们平时实例化一个对象是怎么做的,包名+类 类名 = new 包名+类(),然后看看上图,就明了。写全路径是为了解决导包的问题。

    6 修改生成的apk名字和备份mapping 文件
    //App同级目录中新建一个APK文件夹

    def apkUrl = file('../APK')
    applicationVariants.all { variant ->
                    variant.outputs.each { output ->
                        //修改apk名字并输出到指定位置
                        def fiName
                        if (variant.productFlavors[0].name == "internal") {
                            fiName = "Xiaolaba_a_build_${variant.productFlavors[0].name}_${releaseCode}.apk"
                        } else {
                            fiName = "School_a_v${defaultConfig.versionName}_${variant.productFlavors[0].name}_${releaseCode}.apk"
                        }
                        output.outputFile = new File(apkUrl, fiName)
                        //备份mapping文件
                        if (variant.getBuildType().isMinifyEnabled()) {
                            variant.assemble.doLast {
                                copy {
                                    from variant.mappingFile
                                    into "${rootDir}/APK"
                                    rename { String fileName ->
                                        "mapping-${fiName}.txt"
                                    }
                                }
                            }
                        }
                    }
    
                }
    

    总结

    到此,多渠道的打包就已经完成了。不过还想提一下如何令build.gradle 这个文件如何变得优雅起来

    首先,在app的build.gradle中新建一个config.gradle

    其次 在build.gradle中引入config.gradle,project代表当前的build.gradle 定义好这些参数后就可以用了。

    这是我在项目中用到的config.gradle xxxxx代表一些敏感信息,所以在这里隐去
    ext {
        android = [
                compileSdkVersion: 23,
                buildToolsVersion: "26.0.0",
                minSdkVersion    : 8,
                targetSdkVersion : 23
        ]
        //基础配置
        dependency = [
                gridlayout  : 'com.android.support:gridlayout-v7:23.4.0',
                recyclerview: 'com.android.support:recyclerview-v7:23.4.0',
                multidex    : 'com.android.support:multidex:1.0.0',
                gson        : 'com.google.code.gson:gson:2.7',
                support     : 'com.android.support:support-v13:23.4.0'
        ]
        //业务地址
        urlSetting = [
                ethernet_addr: "xxxxx",
                dev_addr     : "xxxxx",
                school_addr     : "xxxxx",
                tyd_qdmy_addr:"xxxxx"
    
        ]
        //多渠道相关
        flavorsSetting = [
                app_id_tyd       : "xxxxx",
                app_name_tyd     : "xxxxx",
    
                app_id_qdmy      : "xxxxx",
                app_name_qdmy    : "xxxxx",
    
                app_id_school    : "xxxxx",
                app_name_school  : "xxxxx",
                app_name_internal: "xxxxx"
        ]
    
        //版本相关
        def versionCode = getVersionCode(releaseTimeAndVersionCode())
        def versionName = getVersionName()
    
        versionSettting = [
                versionCode: versionCode,
                versionName: versionName
        ]
    
    }
    
    
    def releaseTimeAndVersionCode() {
        String time = new Date().format("yyMMdd", TimeZone.getTimeZone("UTC"))
        return time.substring(1, time.length())
    }
    
    def getVersionCode(String version) {
        return Integer.parseInt(version)
    }
    
    def getVersionName() {
        def versionFile = file('version.properties')
        if (versionFile.exists()) {
            def Properties versionProps = new Properties()
            versionProps.load(new FileInputStream(versionFile))
            def versionCode = versionProps['versionName'].toString()
            return versionCode
        } else {
            throw new GradleException("Could not find version.properties!")
        }
    }
    

    好了,多渠道打包总结就到此结束了。有不明白的地请留言。

    相关文章

      网友评论

        本文标题:AndroidStudio 多渠道打包实践总结

        本文链接:https://www.haomeiwen.com/subject/sprgrxtx.html