Android studio gradle 打包 那些事
2015-12-08 14:56
786 查看
总结了一下 目前觉得比较好用的gradle 和一些打包 经验。放在这里。
首先说下 渠道号 这个概念,我们经常会统计我们的api 访问来源 是来自于那个app store,这有利于 我们针对性的推广。也可以知道用户的分布情况,目前我们的做法通常是这样的:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151207174715996-1851553664.png)
然后在我们的自定义application里面 定义一个函数 来取得这个渠道号
然后再到gradle 脚本里面 动态更改manifest编译时的 meta data里面的值,这个方法是目前流传最广也是使用最多的方法,但是有个缺陷是速度太慢了。
随着我们app的扩展,本身我们编译一次就要很久的时间,然后你想想 至少还要分为debug和release2个版本,然后各种渠道 什么360 pp 百度 豌豆荚 锤子 小米 华为
之类7788 起码20个以上的渠道 再加上debug 和release 你想想 动不动 就是40几个版本,你要是再在gradle 修改脚本来做这件事,后果就是你编译一次 产出
就要很久很久,因为你每次修改完manifest文件里的meta data 都会重新编译一次,太浪费时间了!
所以我们采用下面的方法:
首先我们可以看一下 apk 这个文件 解压缩以后的结构:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151207180056590-2050658963.png)
看一下这个就知道了,我们可以想一下 能否把我们的渠道号 放到这个路径下面呢?让我们的android app代码来读取这个文件路径下的渠道号,然后想办法在build出来的apk里面直接在这个路径下
放一个渠道号不就行了么?这样只用build 一次,修改n次 即可得到我们需要的n个渠道包了!
首先我们来修改我们的app代码:
好,然后我们来编写脚本,这个脚本也很简单,拿到build出来的apk以后 就打开这个zip文件,然后往里面写一个我们规定好的那个格式的文件即可:
注意这是python代码,当然你如果不会python 用java也可以做。
你看,这样就可以完成我们快速生成渠道包的功能了,哪怕你有1000个渠道包需要打,你也只需要编译一次,然后稍微修改一下这个脚本,即可自动生成1000个渠道包。
然后接着看下一个:
如何配置签名信息,大家都知道android的 签名资源一般都是很宝贵的,一个组 可能只有1-2个 管理者能拿到那个原始的keystore。所以我们当然不能在我们的版本库
里面上传这个keystore文件 对吧,尤其做开源项目的时候更是如此,所以有下面的解决方法:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151208112438871-1651520668.png)
你看 我们可以把签名文件定义在外面~~
然后继续修改build.gradle文件,就是你要打版本的 那个project下的build.gradle文件,别改错了!
混淆开关你们自己决定开不开~~
最后说一下 多渠道打包的gradle问题,前面那个 python脚本 已经告诉了大家 如何针对渠道号这一需求 进行多渠道打包。
有兴趣的人可以扩展一下那个脚本,把apk的命名也可以规范一下。这是比较好的习惯。
当然了 关于多渠道打包 还有一种情况就是 比如某些应用市场 或者 某些渠道 非要让你加入他们的sdk什么的 才让你发布
那针对于这种情况,我们python 脚本 直接修改apk 这个zip包 就搞不定了。这种情况就需要 用gradle来解决。下面给出一个例子,
以后大家可以针对性的 也进行配置!
我们假设 现在要发2个版本,一个版本 要用EventBus的代码 还有一个版本不需要。
然后看下我们activity的代码 就增加了一行:
然后我们选择devRelease 作为我们的build varint看一下日志输出什么:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151208145314590-855950668.png)
发现 这里是找不到eventBus这个包的。
然后我们看下modifyDevRelease 看看是什么效果:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151208145431558-526287344.png)
发现 这个eventBus已经打进去了~~
到这,基本上android studio gradle 和 python配合打包的一些主要部分就讲解结束了。
首先说下 渠道号 这个概念,我们经常会统计我们的api 访问来源 是来自于那个app store,这有利于 我们针对性的推广。也可以知道用户的分布情况,目前我们的做法通常是这样的:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151207174715996-1851553664.png)
然后在我们的自定义application里面 定义一个函数 来取得这个渠道号
package com.example.administrator.gradletest; import android.app.Application; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; /** * Created by Administrator on 2015/12/7. */ public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); } private String getChannel(Context context) { try { PackageManager pm = context.getPackageManager(); ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(),PackageManager.GET_META_DATA); return appInfo.metaData.getString("channel"); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return ""; } }
然后再到gradle 脚本里面 动态更改manifest编译时的 meta data里面的值,这个方法是目前流传最广也是使用最多的方法,但是有个缺陷是速度太慢了。
随着我们app的扩展,本身我们编译一次就要很久的时间,然后你想想 至少还要分为debug和release2个版本,然后各种渠道 什么360 pp 百度 豌豆荚 锤子 小米 华为
之类7788 起码20个以上的渠道 再加上debug 和release 你想想 动不动 就是40几个版本,你要是再在gradle 修改脚本来做这件事,后果就是你编译一次 产出
就要很久很久,因为你每次修改完manifest文件里的meta data 都会重新编译一次,太浪费时间了!
所以我们采用下面的方法:
首先我们可以看一下 apk 这个文件 解压缩以后的结构:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151207180056590-2050658963.png)
看一下这个就知道了,我们可以想一下 能否把我们的渠道号 放到这个路径下面呢?让我们的android app代码来读取这个文件路径下的渠道号,然后想办法在build出来的apk里面直接在这个路径下
放一个渠道号不就行了么?这样只用build 一次,修改n次 即可得到我们需要的n个渠道包了!
首先我们来修改我们的app代码:
package com.example.administrator.gradletest; import android.app.Application; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.util.Log; import java.io.IOException; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Created by Administrator on 2015/12/7. */ public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); } //这段代码的作用就是遍历自己的apk包 把包里的文件名全找到 //然后找到某个META-INF/mtchannel_xiaomishangcheng 这样格式的文件即可 //然后把xiaomishangcheng 这个字符串提取出来返回就是得到的渠道号了 private String getChannelByFile(Context context) { ApplicationInfo appinfo = context.getApplicationInfo(); String sourceDir = appinfo.sourceDir; String ret = ""; ZipFile zipfile = null; try { zipfile = new ZipFile(sourceDir); Enumeration<?> entries = zipfile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = ((ZipEntry) entries.nextElement()); String entryName = entry.getName(); Log.v("burning","entryName=="+entryName); if (entryName.startsWith("META-INF/mtchannel")) { ret = entryName; break; } } } catch (IOException e) { e.printStackTrace(); } finally { if (zipfile != null) { try { zipfile.close(); } catch (IOException e) { e.printStackTrace(); } } } String[] split = ret.split("_"); if (split != null && split.length >= 2) { return ret.substring(split[0].length() + 1); } else { return ""; } } // // // private String getChannel(Context context) { // try { // PackageManager pm = context.getPackageManager(); // // ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(),PackageManager.GET_META_DATA); // return appInfo.metaData.getString("channel"); // // } catch (PackageManager.NameNotFoundException e) { // e.printStackTrace(); // } // return ""; // } }
好,然后我们来编写脚本,这个脚本也很简单,拿到build出来的apk以后 就打开这个zip文件,然后往里面写一个我们规定好的那个格式的文件即可:
注意这是python代码,当然你如果不会python 用java也可以做。
# coding=UTF-8 import zipfile #这个就是你build完以后输出的apk包的路径 apkpath = 'C:/Users/Administrator/GradleTest/app/build/outputs/apk/app-debug.apk' #这个就是随便建立一个空文件就可以了 一会要把这个文件写入apk emptypath = 'C:/Users/Administrator/GradleTest/app/build\outputs/apk/none' zipped = zipfile.ZipFile(apkpath, 'a', zipfile.ZIP_DEFLATED) #这个就是用format的方法 给上面那个空文件重命名一下。 empty_channel_file = "META-INF/mtchannel_{channel}".format(channel='xiaomishangcheng') #命名结束以后 就直接把这个空文件写入到apk中即可 zipped.write(emptypath,empty_channel_file)
你看,这样就可以完成我们快速生成渠道包的功能了,哪怕你有1000个渠道包需要打,你也只需要编译一次,然后稍微修改一下这个脚本,即可自动生成1000个渠道包。
然后接着看下一个:
如何配置签名信息,大家都知道android的 签名资源一般都是很宝贵的,一个组 可能只有1-2个 管理者能拿到那个原始的keystore。所以我们当然不能在我们的版本库
里面上传这个keystore文件 对吧,尤其做开源项目的时候更是如此,所以有下面的解决方法:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151208112438871-1651520668.png)
你看 我们可以把签名文件定义在外面~~
然后继续修改build.gradle文件,就是你要打版本的 那个project下的build.gradle文件,别改错了!
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.1" //配置签名信息 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 { release { //告诉gradle 打release版本的时候使用的签名信息 signingConfig signingConfigs.release //无效资源不要打包进release版本 shrinkResources true minifyEnabled false 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' }
混淆开关你们自己决定开不开~~
最后说一下 多渠道打包的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的代码 就增加了一行:
try { Class.forName("de.greenrobot.event.EventBus"); Log.v("MainActivity","加载到EventBus包"); } catch (ClassNotFoundException e) { Log.v("MainActivity","找不到EventBus包"); e.printStackTrace(); }
然后我们选择devRelease 作为我们的build varint看一下日志输出什么:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151208145314590-855950668.png)
发现 这里是找不到eventBus这个包的。
然后我们看下modifyDevRelease 看看是什么效果:
![](http://images2015.cnblogs.com/blog/365799/201512/365799-20151208145431558-526287344.png)
发现 这个eventBus已经打进去了~~
到这,基本上android studio gradle 和 python配合打包的一些主要部分就讲解结束了。
相关文章推荐
- android设备获取 关于手机-》手机名称
- Android基于插件的开发
- android中list在remove()时出现java.lang.IndexOutOfBoundsException异常
- 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高
- android加壳利器-apkprotectlite
- androidstudio的Rendering Problems Missing styles错误解决
- Android——客户端日期定制显示
- 【原】Android高德地图开发——路况+定位
- Android群英传》读书笔记 (4) 第八章 Activity和Activity调用栈分析 + 第九章 系统信息与安全机制 + 第十章 性能优化
- Android硬件加速
- Android SharedPreferences使用以及原理详解
- Android中监听Home键的4种方法总结
- Ant开篇之安装
- Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧
- android中ViewPager图片滑动和自动播放
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
- Android开发艺术探索》读书笔记 (12) 第12章 Bitmap的加载和Cache
- 《Android开发艺术探索》读书笔记 (11) 第11章 Android的线程和线程池
- Android setAdapter addHeaderView 报错解决方案
- 《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制