- 浏览: 409343 次
- 性别:
- 来自: 福州
最新评论
-
野牛精:
感谢楼主分享,帮大忙了。
android ftp 客户端编写(ftp4j) -
happytianqiu:
你好,我最近也在搞这个,能发个demo吗,邮箱是:624951 ...
开发android机顶盒应用 事件,焦点处理 -
zhunanfengfeimeng:
http://www.iteye.comhttp://www. ...
android ftp 客户端编写(ftp4j) -
icyttea:
好棒!感谢楼主分享
vlc for android录制视频与截图 -
clwwlc:
有demo吗
开发android机顶盒应用 事件,焦点处理
打包,是一个经常会遇到的问题,写个脚本就可以解决了.不同的脚本,速度不同.如果使用ant,需要编译,这个时间较长,可以修改下任务,只编译一次就可以了.
sdk里面提供了一堆工具,打包就是用这些工具做的.
在看了几篇文章后,也写了一个类,实现了打包的功能.
需要用到apktool.jar,
sdk里面提供了一堆工具,打包就是用这些工具做的.
在看了几篇文章后,也写了一个类,实现了打包的功能.
需要用到apktool.jar,
原本是python写的一个脚本,具体是哪个大侠,本人也不清楚. 在这里感谢下. 这是python脚本 #!/usr/bin/python # coding=utf-8 import os import shutil def readChannelfile(filename): f = file(filename) while True: line = f.readline().strip('\n') if len(line) == 0: break else: channelList.append(line); f.close() def backUpManifest(): if os.path.exists('./AndroidManifest.xml'): os.remove('./AndroidManifest.xml') manifestPath = './temp/AndroidManifest.xml' shutil.copyfile(manifestPath, './AndroidManifest.xml') def modifyChannel(value): tempXML = '' f = file('./AndroidManifest.xml') for line in f: if line.find('wap') > 0: line = line.replace('wap', value) tempXML += line f.close() output = open('./temp/AndroidManifest.xml', 'w') output.write(tempXML) output.close() tempXML = '' f = file('./agency.txt') for line in f: if line.find('defaultid') > 0: line = line.replace('defaultid', value) tempXML += line f.close() output = open('./temp/assets/defaultid.txt', 'w') output.write(tempXML) output.close() unsignApk = r'./bin/%s_%s_unsigned.apk'% (easyName, value) cmdPack = r'java -jar apktool.jar b temp %s'% (unsignApk) os.system(cmdPack) unsignedjar = r'./bin/%s_%s_unsigned.apk'% (easyName, value) signed_unalignedjar = r'./bin/%s_%s_signed_unaligned.apk'% (easyName, value) signed_alignedjar = r'./bin/%s_v%s_%s_%s_%s_%s.apk'% (easyName, versionid, productid, value, packtime, customerid) cmd_sign = r'jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore %s -storepass %s -keypass %s -signedjar %s %s %s'% (keystore, storepass, keypass, signed_unalignedjar, unsignedjar, alianame) cmd_align = r'zipalign -v 4 %s %s' % (signed_unalignedjar, signed_alignedjar) os.system(cmd_sign) os.remove(unsignedjar) os.system(cmd_align) os.remove(signed_unalignedjar) dir = r'./bin/%s'% (value) os.mkdir(dir) shutil.move(signed_alignedjar,dir) channelList = [] apkName = 'dfadfadf.apk' easyName = apkName.split('.apk')[0] keystore='./keystore/Android.key' storepass='' keypass='' alianame='' packtime='2014091215' customerid='' productid='10' versionid='1.0.0' output_apk_dir="./bin" if os.path.exists(output_apk_dir): shutil.rmtree(output_apk_dir) readChannelfile('./channel') print '-------------------- your channel values --------------------' print 'channel list: ', channelList cmdExtract = r'java -jar apktool.jar d -f -s %s temp'% (apkName) os.system(cmdExtract) backUpManifest() for channel in channelList: modifyChannel(channel) if os.path.exists('./temp'): shutil.rmtree('./temp') if os.path.exists('./AndroidManifest.xml'): os.remove('./AndroidManifest.xml') print '-------------------- Done --------------------' 不废话,直接上代码: import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; /** * @author: archko 2014/9/16 :12:46 */ public class JPackage { ArrayList<String> mChannelList=new ArrayList<String>(); private String mChannelFile="channel"; private String mParamsFile="params"; /** * 打的包名, */ String apkName; /** * 签名的地址 */ String keystorepath; /** * 签名密码 */ String storepass; /** * 密钥密码 */ String keypass; /** * 签名的别名 */ String alianame; /** * 打包时间 */ String packtime; /** * 版本号 */ String versionname; /** * 标识,固定的 */ String identity; /** * */ String customerid; /** * 旧的渠道名.就是要替换的位置. */ String oldchannel="defaultid"; /** * 是否分别放入不同的目录中. */ String splitdir; static String cmd_header="cmd.exe /C "; /** * 需要替换的assets里面的名字. */ String assetsname; String assetchannel; public void runCmd(String cmd) { Runtime rt=Runtime.getRuntime(); try { Process p=rt.exec(cmd_header+cmd); // p.waitFor(); BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream())); String msg=null; while ((msg=br.readLine())!=null) { System.out.println(msg); } } catch (Exception e) { e.printStackTrace(); } } public ArrayList<String> readFile(String path) { ArrayList<String> lines=new ArrayList<String>(); InputStream is=null; InputStreamReader reader=null; BufferedReader br=null; try { is=new FileInputStream(path); reader=new InputStreamReader(is, "UTF-8"); br=new BufferedReader(reader); String row; try { while ((row=br.readLine())!=null) { lines.add(row); } } catch (OutOfMemoryError e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } try { if (null!=br) { br.close(); } if (null!=reader) { reader.close(); } } catch (IOException e) { e.printStackTrace(); } return lines; } public void readChannels(String path) { mChannelList=readFile("./"+path); } public void backManifest() throws Exception { File file=new File("./temp/AndroidManifest.xml"); if (!file.exists()) { throw new Exception("没有AndroidManifest文件"); } File dest=new File("./AndroidManifest.xml"); file.renameTo(dest); if (!isEmpty(assetsname)) { file=new File("./temp/assets/"+assetsname); if (!file.exists()) { throw new Exception("没有"+assetsname+"文件"); } dest=new File("./"+assetsname); file.renameTo(dest); } } private void readParamsFromFile(String[] args) throws Exception { ArrayList<String> params=readFile("./"+mParamsFile); System.out.println("params"+params); if (params.size()<1) { throw new Exception("打包参数不对."); } String[] line; for (String ss : params) { line=ss.split("="); if ("apkName".equals(line[0])) { apkName=line[1]; } else if ("keystorepath".equals(line[0])) { keystorepath=line[1]; } else if ("storepass".equals(line[0])) { storepass=line[1]; } else if ("keypass".equals(line[0])) { keypass=line[1]; } else if ("alianame".equals(line[0])) { alianame=line[1]; } else if ("packtime".equals(line[0])) { packtime=line[1]; } else if ("versionname".equals(line[0])) { versionname=line[1]; } else if ("identity".equals(line[0])) { identity=line[1]; } else if ("customerid".equals(line[0])) { customerid=line[1]; } else if ("oldchannel".equals(line[0])) { oldchannel=line[1]; } else if ("splitdir".equals(line[0])) { splitdir=line[1]; } else if ("assetsname".equals(line[0])) { assetsname=line[1]; } else if ("assetchannel".equals(line[0])) { assetchannel=line[1]; } } System.out.println("参数为:"+String.format("apkName:%s, keystorepath:%s, storepass:%s, keypass:%s, alianame:%s, "+ "packtime:%s, versionname:%s,identity:%s, oldchannel:%s, splitdir:%s", apkName, keystorepath, storepass, keypass, alianame, packtime, versionname, identity, oldchannel, splitdir)); } private void decompileApk() throws Exception { File file=new File("./temp"); if (!file.exists()) { file.mkdir(); } //System.setProperty("java.class.path", ".;"+System.getProperty("java.class.path")); String cmd="java -jar apktool.jar d -f -s "+apkName+" temp"; //System.out.println("cmd:"+cmd); runCmd(cmd); file=new File("./temp/AndroidManifest.xml"); if (!file.exists()) { throw new Exception("decompile error."); } file=new File("./temp/res"); if (!file.exists()) { throw new Exception("decompile error."); } if (!file.exists()) { throw new Exception("decompile error."); } } /** * %s_v%s_%s_%s_%s_%s.apk"% (easyName, versionid, productid, value, packtime, customerid) * * @param channel */ public String generateFileName(String channel) { StringBuilder sb=new StringBuilder(); sb.append(apkName); if (!isEmpty(versionname)) { sb.append("_").append(versionname); } if (!isEmpty(identity)) { sb.append("_").append(identity); } sb.append("_").append(channel); if (!isEmpty(packtime)) { sb.append("_").append(packtime); } if (!isEmpty(customerid)) { sb.append("_").append(customerid); } sb.append(".apk"); System.out.println("包名:"+sb); return sb.toString(); } public void modifyChannel(String channel) { try { String apkName=generateFileName(channel); System.out.println("替换渠道号:"+oldchannel+"为:"+channel+" apk:"+apkName); replaceChannels(channel); File file; if ("true".equals(splitdir)) { file=new File("./bin/"+channel); } else { file=new File("./bin/"); } if (!file.exists()) { file.mkdirs(); } String unsignApk="./bin/_unsigned.apk"; System.out.println("unsignApk:"+unsignApk); String cmdPack=String.format("java -jar apktool.jar b temp %s", unsignApk); runCmd(cmdPack); String unsignedjar="./bin/_unsigned.apk"; String signed_unalignedjar=String.format("./bin/%s_signed_unaligned.apk", ""); String cmd_sign=String.format("jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore %s -storepass %s"+ " -keypass %s -signedjar %s %s %s", keystorepath, storepass, keypass, signed_unalignedjar, unsignedjar, alianame); String signed_alignedjar=""; if ("true".equals(splitdir)) { signed_alignedjar="./bin/"+channel+File.separator+apkName; } else { signed_alignedjar="./bin/"+apkName; } String cmd_align=String.format("zipalign -v 4 %s %s", signed_unalignedjar, signed_alignedjar); runCmd(cmd_sign); runCmd(cmd_align); file=new File(unsignApk); if (file.exists()) { file.delete(); } file=new File(signed_unalignedjar); if (file.exists()) { file.delete(); } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } private void replaceChannels(String channel) throws IOException { String manifest=readStringFromFile("./AndroidManifest.xml"); manifest=manifest.replaceAll(oldchannel, channel); File file=new File("./temp/AndroidManifest.xml"); FileWriter fw=new FileWriter(file); fw.write(manifest); fw.close(); if (!isEmpty(assetsname)) { replaceAssets(channel); } } private void replaceAssets(String channel) { ArrayList<String> strings=readFile("./"+assetsname); StringBuilder result=new StringBuilder(); for (String s : strings) { String rs=s.replaceAll(assetchannel, channel); System.out.println("replace assets:"+rs); result.append(rs).append("\r\n"); } File file=new File("./temp/assets/"+assetsname); FileWriter fw=null; try { fw=new FileWriter(file); fw.write(result.toString()); fw.close(); } catch (IOException e) { e.printStackTrace(); } } private void build(String[] args) throws Exception { //System.out.println(System.getProperty("java.class.path")); readParamsFromFile(args); readChannels(mChannelFile); if (mChannelList.size()<1) { } System.out.println("渠道号:"+mChannelList); decompileApk(); backManifest(); File file; file=new File("./bin/"); System.out.println("file:"+file.exists()); if (file.exists()) { deleteDir(file); } for (String channel : mChannelList) { modifyChannel(channel); } } public static boolean isEmpty(String s) { return length(s)==0; } public static int length(final String s) { return s!=null ? s.length() : 0; } public static String readStringFromFile(String sFileName) { if (null==(sFileName)) return null; final StringBuffer sDest=new StringBuffer(); final File f=new File(sFileName); if (!f.exists()) { return null; } try { FileInputStream is=new FileInputStream(f); BufferedReader br=new BufferedReader(new InputStreamReader(is)); try { String data=null; while ((data=br.readLine())!=null) { sDest.append(data); } } catch (IOException ioex) { ioex.printStackTrace(); } finally { is.close(); is=null; br.close(); br=null; } } catch (Exception ex) { ex.printStackTrace(); } return sDest.toString().trim(); } public static void deleteDir(File dir) { if (dir==null||!dir.exists()||!dir.isDirectory()) return; // 检查参数 for (File file : dir.listFiles()) { if (file.isFile()) file.delete(); // 删除所有文件 else if (file.isDirectory()) deleteDir(file); // 递规的方式删除文件夹 } //dir.delete();// 删除目录本身 } public static void main(String[] args) throws Exception { String OS=System.getProperty("os.name").toLowerCase(); if (OS.contains("linux")||OS.contains("mac")||OS.contains("os")) { cmd_header=" "; } System.out.println("cmd_header:"+cmd_header); JPackage jPackage=new JPackage(); long start=System.currentTimeMillis(); jPackage.build(args); long end=System.currentTimeMillis(); end=end-start; String result=millisToString(end, true); System.out.println("总花费时间:"+result); } static String millisToString(long millis, boolean text) { boolean negative=millis<0; millis=java.lang.Math.abs(millis); millis/=1000; int sec=(int) (millis%60); millis/=60; int min=(int) (millis%60); millis/=60; int hours=(int) millis; String time; DecimalFormat format=(DecimalFormat) NumberFormat.getInstance(Locale.US); format.applyPattern("00"); if (text) { if (millis>0) time=(negative ? "-" : "")+hours+"h"+format.format(min)+"min"; else if (min>0) time=(negative ? "-" : "")+min+"min"; else time=(negative ? "-" : "")+sec+"s"; } else { if (millis>0) time=(negative ? "-" : "")+hours+":"+format.format(min)+":"+format.format(sec); else time=(negative ? "-" : "")+min+":"+format.format(sec); } return time; } } 39个包,6m左右,2分钟左右完成. 前面的python脚本还存在一些问题,比如环境不好配置,(linux下是可以的,mac下,cygwin下会提示aapt这些找不到,可能是64位的原因).渠道名有空格无法识别啊. 顺便写了两个脚本,bat在windows下用,sh在*nix下用. 最后的包名;pn_v1.0.0_111_3g_2014091614_abc.apk 所以上面的参数可以不写,比如你的包,没有需要identity这个东西,就可以放空.identity= 就行了.但是不能加参数,需要的话,自己修改源码了. 配置的参数为params文件,上面源码里有了: apkName=your_pkg.apk keystorepath=./keystore/Android.key storepass=your_storepass keypass=your_keypass alianame=your_alianame 上面这些不用说了,必须的,但是如果keypass不写,默认与storepass一样. 下面这些影响最后的命名 packtime=2014091215 打包的时间,可以为空 customerid=abc 可为空. identity=111 可为空. versionname=v1.0.0 可为空. oldchannel=wap 需要替换的渠道名字,manifest里面的 splitdir=true 是否为单个渠道建立目录,分开放包. assetsname=assets_channel.txt 如果你要在assets目录下有一个渠道文件,就可以在这里写明. assetchannel=defaultid assets下的渠道文件中的需要替换的名字. 替换是使用正则,所以看清楚了.不要弄错了. destApkName=yourakpname 这个是你的apk名字前缀,后面加的,源码在压缩包中,上面的就不修改了. 最后的文件,如果参数都有的话: myapk_v1.0.0_31_3g_2014091811_111.apk channel就是一个文本文件,一行一个渠道,如果是在linux下,使用windows下的此文件,有可能换行符会出现问题,如果是这样,就可以把行尾的删除,再回车换行. 特别说下sh文件: export JAVA_HOME=/media/archko/res_compile/jdk1.7.0_67 export ANDROID_SDK=/media/archko/linux_res/android-sdk-linux export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$ANDROID_SDK:$ANDROID_SDK/platforms-tools:$ANDROID_SDK/tools:$ANDROID_SDK/build-tools/20.0.0: 这些路径自己设置好.否则可能找不到aapt,这些需要的命令. 最后运行:sh pkg.sh 或双击bat就可以打包了. 或者直接运行java -Xms128m -Xmx512m -jar pkg.jar 再或者你编译了源码,可以 java JPackage来打包.
- JPKG_custom.zip (2 MB)
- 下载次数: 105
发表评论
-
vlc for android录制视频与截图
2014-09-08 18:31 8031首先说明,这不算原 ... -
android百度地图转为高德地图
2014-08-11 11:09 2964使用百度地图也不少时间了,但是一直出现无法解决的问题,在官 ... -
编译 i9000的cm系统
2014-08-04 13:10 1596[color=red][b]此文 并不 ... -
mp4v2 保存h264流
2014-05-01 21:15 11827大侠已经完成了很多操作了,唯一不足的是,工程完整性差一些,而且 ... -
baidumap的缩放到看到所有点
2014-04-09 21:03 1464之前使用1.3.5版本的sdk,通过调用mapviewcont ... -
ViewPager 查看图片
2014-02-13 12:59 4525一个图片查看器 , app到处都是 , 但那是别人的. 现在的 ... -
机顶盒 页面 选中后的 动画
2013-12-05 09:39 2184前面已经说过了,对于机顶盒的焦点的处理. 相信有不少人看 ... -
引爆你的图片浏览, ListView 大图片
2013-11-05 07:58 1314之前发现,ListView里面的图片资源越占越大,特别是当 ... -
微博开放源码
2013-10-23 12:09 1035微博程序已经发布不少时间了,但一直也没有很多用户使用,主要在用 ... -
Mupdf 缩小apk包,减少字体
2013-10-20 15:53 3723在以前的apv中,字体占了很大的一部分,如果去除cjk字体 ... -
ActionBar appcompat 解决碎片化问题
2013-09-15 16:58 2178actionbarsherlock 这个在api11以下的系统 ... -
android机顶盒获取有线mac
2013-09-02 16:09 5503直接上代码: public static String ... -
android竖着的seekbar
2013-08-22 20:33 5534以前网上有位虾士发过一篇文章是关于竖着的seekbar,但是也 ... -
新浪微博oauth2.0 自动认证
2013-08-13 09:01 0oauth2.0作者认为它不先进,都放弃了.但是oauth2. ... -
android 颜表情.
2013-07-20 21:16 1858在使用TagsViewGroup 流布局后,我替换了原来的Gr ... -
flow 流布局.
2013-07-13 20:06 1306在git上看到一个FlowingViewGroup,代码有点旧 ... -
开发android机顶盒应用 事件,焦点处理
2013-07-13 19:58 19838机顶盒应用不同于手机 ... -
android 磁盘缓存.
2013-07-13 19:30 5291开发一个app,特别是图片的app,免不了要存储图片,内存缓存 ... -
TextView 文字淡入效果
2013-04-15 13:34 3498一个文本渐渐地从左到右的显示。 几步就可以了实现了。利用的是V ... -
制造垃圾短信
2013-01-28 14:25 1429往系统中插入一条短信息,然后在通知栏中通知,点击通知栏后可以在 ...
相关推荐
强两天根据公司项目需要写了一个P处理工具,实现了Android批量打混淆包。使用及说明这里就不写了,写在文章中去吧,同时附图:http://blog.csdn.net/ggdffftghjndjnd/article/details/16339851
"android自动化批量打渠道包"这个话题就是解决这一问题的有效方案,通过自动化流程来提高效率。 首先,我们要理解Android的构建过程。Android应用程序的构建主要由Gradle脚本驱动,它定义了应用的编译配置和打包...
本教程将详细讲解如何在Unity3D中进行Android渠道包的批量构建,以便实现一键打包,提高效率。 一、准备工作 1. Unity3D安装:确保你已经安装了最新版本的Unity3D编辑器,并且该版本支持Android平台的构建。 2. ...
以下将详细解释如何利用Python进行Android批量多渠道打包。 一、Python环境搭建 首先,你需要在你的系统(Windows、Linux或Mac)上安装Python。确保Python版本至少为3.x,因为早期的2.x版本已不再维护。你可以访问...
在Android应用开发过程中,为了发布到不同的应用市场或者进行A/B测试,往往需要构建多个渠道包,每个渠道对应一个特定的标识。手动进行这个过程既耗时又容易出错。"android多渠道批量打包工具"就是为了解决这个问题...
本资源将详细介绍如何使用Ant进行批量多渠道打包Android应用。 首先,你需要在你的项目中集成Ant。这通常意味着在项目根目录下创建一个名为`build.xml`的Ant构建文件。这个文件是Ant的配置中心,它定义了构建过程中...
本文将深入探讨“android 批量渠道打包工具”的核心功能、工作原理以及如何使用。 批量渠道打包工具是开发者在发布应用时的重要辅助工具,它极大地提高了效率,避免了手动为每个渠道创建单独APK的繁琐过程。传统的...
在Android平台上,为了发布游戏,通常需要构建多个渠道包,每个渠道对应不同的应用市场或者推广渠道,如Google Play、华为应用市场、小米应用商店等。这些渠道包需要包含特定的标识以便追踪和管理。 批量构建渠道包...
详细解释文章地址: 《Android 自动编译、打包生成apk文件 4 - 多渠道批量打包》 http://blog.csdn.net/androiddevelop/article/details/11619635
下面我们将深入探讨如何使用Python批量创建Android渠道包。 首先,我们需要理解Android的构建系统。Android Studio使用Gradle作为默认的构建工具,它允许我们通过修改build.gradle文件来配置构建变量。在`default...
手动处理这些渠道包不仅耗时且容易出错,因此,使用“android多渠道批量打包工具命令版”可以极大地提高效率。这个工具允许开发者通过简单的命令行操作,快速生成不同渠道的APK,无需重复进行繁琐的配置步骤。 首先...
本示例详细介绍了如何进行Android项目的批量打包操作,以满足一次性生成多个渠道包的需求。 首先,了解批量打包的背景和原因。在Android应用发布时,我们通常需要为每个推广渠道添加特定的标识(例如渠道ID),以便...
"android批量打包工具"就是为了解决这一问题而设计的,它能够帮助开发者快速、高效地完成多版本APK的生成。下面我们将深入探讨这个工具的核心功能及其在实际开发中的应用。 首先,该工具的一大亮点是支持渠道号替换...
本资源提供了解决Android APK批量打包过程中的一些关键问题,包括渠道号替换、服务器地址替换、资源替换以及指定文件修改和修改包名等操作。下面将详细解释这些知识点。 1. **渠道号替换**: 在Android应用发布时...
【Eclipse插件-Android项目APK渠道号批量打包工具兰贝】 在Android应用开发过程中,经常需要为不同的分发渠道创建带有特定渠道标识的APK文件,以便追踪每个渠道的下载和用户行为数据。传统的做法是手动修改...
本篇文章将深入探讨"android打包工具多渠道批量打包"这一主题,以及如何利用此类工具提升工作效率。 首先,我们理解一下“多渠道打包”。在Android应用发布时,通常会针对不同的推广渠道(如应用市场、广告网络等)...
在Android应用开发中,"分分钟打几百个渠道包"是指快速为不同的应用分发渠道创建定制的APK文件。每个渠道包通常包含特定的标识符,以便追踪安装来源,这对于广告推广、数据分析以及合作伙伴管理至关重要。下面我们将...
这里我们将深入探讨“Android渠道批量打包”和“Android反编译”的相关技术,以及如何利用提供的工具来实现这些操作。 一、Android渠道打包 Android渠道打包主要是为了在分发应用时区分不同的推广渠道,以便跟踪每...