• Android studio gradle 打包 那些事


    总结了一下 目前觉得比较好用的gradle 和一些打包 经验。放在这里。

    首先说下 渠道号 这个概念,我们经常会统计我们的api 访问来源 是来自于那个app store,这有利于 我们针对性的推广。也可以知道用户的分布情况,目前我们的做法通常是这样的:

    然后在我们的自定义application里面 定义一个函数 来取得这个渠道号

     1 package com.example.administrator.gradletest;
     2 
     3 import android.app.Application;
     4 import android.content.Context;
     5 import android.content.pm.ApplicationInfo;
     6 import android.content.pm.PackageManager;
     7 
     8 /**
     9  * Created by Administrator on 2015/12/7.
    10  */
    11 public class BaseApplication extends Application {
    12     @Override
    13     public void onCreate() {
    14         super.onCreate();
    15     }
    16 
    17     private String getChannel(Context context) {
    18         try {
    19             PackageManager pm = context.getPackageManager();
    20 
    21             ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(),PackageManager.GET_META_DATA);
    22             return appInfo.metaData.getString("channel");
    23 
    24         } catch (PackageManager.NameNotFoundException e) {
    25             e.printStackTrace();
    26         }
    27         return "";
    28     }
    29 }

    然后再到gradle 脚本里面 动态更改manifest编译时的 meta data里面的值,这个方法是目前流传最广也是使用最多的方法,但是有个缺陷是速度太慢了。

    随着我们app的扩展,本身我们编译一次就要很久的时间,然后你想想 至少还要分为debug和release2个版本,然后各种渠道 什么360 pp 百度 豌豆荚 锤子 小米 华为

    之类7788 起码20个以上的渠道 再加上debug 和release 你想想 动不动 就是40几个版本,你要是再在gradle 修改脚本来做这件事,后果就是你编译一次 产出

    就要很久很久,因为你每次修改完manifest文件里的meta data 都会重新编译一次,太浪费时间了!

    所以我们采用下面的方法:

    首先我们可以看一下 apk 这个文件 解压缩以后的结构:

    看一下这个就知道了,我们可以想一下 能否把我们的渠道号 放到这个路径下面呢?让我们的android app代码来读取这个文件路径下的渠道号,然后想办法在build出来的apk里面直接在这个路径下

    放一个渠道号不就行了么?这样只用build 一次,修改n次 即可得到我们需要的n个渠道包了!

    首先我们来修改我们的app代码:

     1 package com.example.administrator.gradletest;
     2 
     3 import android.app.Application;
     4 import android.content.Context;
     5 import android.content.pm.ApplicationInfo;
     6 import android.content.pm.PackageManager;
     7 import android.util.Log;
     8 
     9 import java.io.IOException;
    10 import java.util.Enumeration;
    11 import java.util.zip.ZipEntry;
    12 import java.util.zip.ZipFile;
    13 
    14 /**
    15  * Created by Administrator on 2015/12/7.
    16  */
    17 public class BaseApplication extends Application {
    18     @Override
    19     public void onCreate() {
    20         super.onCreate();
    21     }
    22 
    23 
    24     //这段代码的作用就是遍历自己的apk包 把包里的文件名全找到
    25     //然后找到某个META-INF/mtchannel_xiaomishangcheng 这样格式的文件即可
    26     //然后把xiaomishangcheng 这个字符串提取出来返回就是得到的渠道号了
    27     private  String getChannelByFile(Context context) {
    28         ApplicationInfo appinfo = context.getApplicationInfo();
    29         String sourceDir = appinfo.sourceDir;
    30         String ret = "";
    31         ZipFile zipfile = null;
    32         try {
    33             zipfile = new ZipFile(sourceDir);
    34             Enumeration<?> entries = zipfile.entries();
    35             while (entries.hasMoreElements()) {
    36                 ZipEntry entry = ((ZipEntry) entries.nextElement());
    37                 String entryName = entry.getName();
    38                 Log.v("burning","entryName=="+entryName);
    39                 if (entryName.startsWith("META-INF/mtchannel")) {
    40                     ret = entryName;
    41                     break;
    42                 }
    43             }
    44         } catch (IOException e) {
    45             e.printStackTrace();
    46         } finally {
    47             if (zipfile != null) {
    48                 try {
    49                     zipfile.close();
    50                 } catch (IOException e) {
    51                     e.printStackTrace();
    52                 }
    53             }
    54         }
    55 
    56         String[] split = ret.split("_");
    57         if (split != null && split.length >= 2) {
    58             return ret.substring(split[0].length() + 1);
    59 
    60         } else {
    61             return "";
    62         }
    63     }
    64 
    65 //
    66 //
    67 //    private String getChannel(Context context) {
    68 //        try {
    69 //            PackageManager pm = context.getPackageManager();
    70 //
    71 //            ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(),PackageManager.GET_META_DATA);
    72 //            return appInfo.metaData.getString("channel");
    73 //
    74 //        } catch (PackageManager.NameNotFoundException e) {
    75 //            e.printStackTrace();
    76 //        }
    77 //        return "";
    78 //    }
    79 }

    好,然后我们来编写脚本,这个脚本也很简单,拿到build出来的apk以后 就打开这个zip文件,然后往里面写一个我们规定好的那个格式的文件即可:

    注意这是python代码,当然你如果不会python 用java也可以做。

     1 # coding=UTF-8
     2 import zipfile
     3 #这个就是你build完以后输出的apk包的路径
     4 apkpath = 'C:/Users/Administrator/GradleTest/app/build/outputs/apk/app-debug.apk'
     5 #这个就是随便建立一个空文件就可以了 一会要把这个文件写入apk
     6 emptypath = 'C:/Users/Administrator/GradleTest/app/buildoutputs/apk/none'
     7 zipped = zipfile.ZipFile(apkpath, 'a', zipfile.ZIP_DEFLATED)
     8 #这个就是用format的方法 给上面那个空文件重命名一下。
     9 empty_channel_file = "META-INF/mtchannel_{channel}".format(channel='xiaomishangcheng')
    10 #命名结束以后 就直接把这个空文件写入到apk中即可
    11 zipped.write(emptypath,empty_channel_file)

    你看,这样就可以完成我们快速生成渠道包的功能了,哪怕你有1000个渠道包需要打,你也只需要编译一次,然后稍微修改一下这个脚本,即可自动生成1000个渠道包。

    然后接着看下一个:

    如何配置签名信息,大家都知道android的 签名资源一般都是很宝贵的,一个组  可能只有1-2个 管理者能拿到那个原始的keystore。所以我们当然不能在我们的版本库

    里面上传这个keystore文件 对吧,尤其做开源项目的时候更是如此,所以有下面的解决方法:

    你看 我们可以把签名文件定义在外面~~

    然后继续修改build.gradle文件,就是你要打版本的 那个project下的build.gradle文件,别改错了!

     1 apply plugin: 'com.android.application'
     2 
     3 android {
     4     compileSdkVersion 23
     5     buildToolsVersion "23.0.1"
     6 
     7 
     8     //配置签名信息
     9     signingConfigs{
    10         release{
    11             storeFile file(RELEASE_STORE_FILE)
    12             storePassword RELEASE_STORE_PASSWORD
    13             keyAlias RELEASE_KEY_ALIAS
    14             keyPassword RELEASE_KEY_PASSWORD
    15         }
    16     }
    17     defaultConfig {
    18         applicationId "com.example.administrator.gradletest"
    19         minSdkVersion 14
    20         targetSdkVersion 23
    21         versionCode 1
    22         versionName "1.0"
    23     }
    24     buildTypes {
    25         release {
    26             //告诉gradle 打release版本的时候使用的签名信息
    27             signingConfig signingConfigs.release
    28             //无效资源不要打包进release版本
    29             shrinkResources true
    30             minifyEnabled false
    31             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    32         }
    33     }
    34 }
    35 
    36 dependencies {
    37     compile fileTree(dir: 'libs', include: ['*.jar'])
    38     testCompile 'junit:junit:4.12'
    39     compile 'com.android.support:appcompat-v7:23.1.1'
    40     compile 'com.android.support:design:23.1.1'
    41 }

    混淆开关你们自己决定开不开~~

    最后说一下 多渠道打包的gradle问题,前面那个 python脚本 已经告诉了大家 如何针对渠道号这一需求 进行多渠道打包。

    有兴趣的人可以扩展一下那个脚本,把apk的命名也可以规范一下。这是比较好的习惯。

    当然了 关于多渠道打包 还有一种情况就是 比如某些应用市场 或者 某些渠道 非要让你加入他们的sdk什么的 才让你发布

    那针对于这种情况,我们python 脚本 直接修改apk 这个zip包 就搞不定了。这种情况就需要 用gradle来解决。下面给出一个例子,

    以后大家可以针对性的 也进行配置!

    我们假设 现在要发2个版本,一个版本 要用EventBus的代码 还有一个版本不需要。

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        //这里我们定义了2个渠道版本 一个是modifyDev 这个dev包就是会打包进去eventbus的
        //还有一个dev包 则是不会把eventbus打包进去
        productFlavors {
            "modifyDev" {
            }
            "dev"{
    
            }
        }
        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                //命名规则,这个就是主要演示一下groovy闭包操作的
                //前面我们知道多渠道打包还是用python来完成速度是最快的
                output.outputFile = new File(
                        output.outputFile.parent,
                        "custom-${variant.buildType.name}-${variant.versionName}-${variant.productFlavors[0].name}.apk".toLowerCase())
                //把unaligned apk删除掉 看着碍眼
                File unaligned=output.packageApplication.outputFile
                unaligned.delete()
    
            }
        }
    
        signingConfigs{
            release{
                storeFile file(RELEASE_STORE_FILE)
                storePassword RELEASE_STORE_PASSWORD
                keyAlias RELEASE_KEY_ALIAS
                keyPassword RELEASE_KEY_PASSWORD
            }
        }
        defaultConfig {
            applicationId "com.example.administrator.gradletest"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            //我们当然也可以针对debug版本进行配置 这里就省略不进行特殊配置
            debug {
    
            }
            release {
                //告诉gradle 打release版本的时候使用的签名信息
                signingConfig signingConfigs.release
                //无效资源不要打包进release版本
                shrinkResources true
                //release版本我们把扰码打开
                minifyEnabled true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:23.1.1'
        compile 'com.android.support:design:23.1.1'
        //注意看这个地方我们使用的是provided 这样我们在写代码的时候就可以引用这个包下面的所有代码了
        provided 'de.greenrobot:eventbus:2.4.0'
        //但实际上你看只有 modifyDev 这个Flavor 会真正的Compile进去 其他默认情况下 是不会Compile进去的
        modifyDevCompile 'de.greenrobot:eventbus:2.4.0'
    }

    然后看下我们activity的代码 就增加了一行:

    1 try {
    2             Class.forName("de.greenrobot.event.EventBus");
    3             Log.v("MainActivity","加载到EventBus包");
    4         } catch (ClassNotFoundException e) {
    5             Log.v("MainActivity","找不到EventBus包");
    6             e.printStackTrace();
    7         }

    然后我们选择devRelease 作为我们的build varint看一下日志输出什么:

    发现 这里是找不到eventBus这个包的。

    然后我们看下modifyDevRelease 看看是什么效果:

    发现 这个eventBus已经打进去了~~ 

    到这,基本上android studio gradle 和 python配合打包的一些主要部分就讲解结束了。

  • 相关阅读:
    超能英雄第一至四季/全集Heroes迅雷下载
    吸血鬼猎人巴菲第一至八季/全集Buffy迅雷下载
    明星伙伴第一至八季/全集Entourage迅雷下载
    实习医生风云第一至九季/全集Scrubs迅雷下载
    阿里云linux图形界面(centos6)
    linux下mysql的root密码忘记解决方
    wdcp支持两种安装方式
    如何搭建lamp(CentOS7+Apache+MySQL+PHP)环境
    丑女贝蒂第一至四季/全集Ugly Betty迅雷下载
    云服务器 ECS Linux 系统安装图形化桌面 (centos7 ubuntu14)
  • 原文地址:https://www.cnblogs.com/punkisnotdead/p/5029125.html
Copyright © 2020-2023  润新知