APP多平台快速切换
因为公司的APP需要向多平台发布,并且同一份APP源码会切换厂商发多种版本的APP。然而,虽然我有做厂商的区分文件,但每次源码切换厂商总是耗时,而且手动切换(进行文本覆盖),总有时候会有些漏的和错的。特别向AndroidManifest.xml文件,大部分的内容是相同的,但因为有接入第三方的sdk,有些差异的地方需要手动改,多版本维护,会存在错漏。
为此,为了减轻工作量,特意做了个快速替换厂商文件,及部署APK的脚本。
先说下我的思路,gradle命令中
gradle assembleDebug //打包Debug包
gradle assembleRelease //打包Release包
可以进行APK的打包,当然需要部署gradle的环境。
gradle的命令需要jdk8的版本进行支持。
我当前的gradle版本是gradle-3.3
http://download.csdn.net/download/feiniyan4944/10178513
然后通过jarsigner命令可以对APK进行签名
jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore 签名文件 -storepass
密码 -signedjar 打包后的APK路径 未打包的APK路径 别名
又因为上面的命令都是在cmd跑的,然后脚本我选择了bat脚本处理。
剩下的就是对存在差异数据厂商的文件进行处理。但用bat脚本我不会处理这么大量的数据,因为我是做java开发的,于是选择java进行处理了。
先附上效果图一张
好了附上我的bat源码
appbuild.bat
:: 不显示后续命令行及当前命令行
@echo off::选择厂商
set platform=0
::获取当前脚本的路径
set bulidPath=%cd%
::取得上一级工程目录
cd..
set iremotePath=%cd%
::差异厂商的apk存放路径
set folderName=jwzh
:: 版本号
set version=
goto ChoosePlatform
:ChoosePlatform
@echo *******************************
@echo.
@echo 版本打包
@echo.
@echo *******************************
@echo.
@echo.
@echo 请选择厂家版本
@echo 1.百度 baidu
@echo 2.谷歌 google
:: /c按键列表 /m提示内容 /d默认选择 /t等待秒数 /d 必须和 /t同时出现
choice /c:123 /m:"" /d:1 /t:20
if %errorlevel%==1 goto baidu
if %errorlevel%==2 goto google:baidu
set platform=1
set folderName=baidu
@echo 百度版本
goto platformReplace:google
set platform=2
set folderName=google
@echo 谷歌版本
goto platformReplace::java代码厂商文件替换
:platformReplace
@echo 正在编译厂商处理文件...
cd %bulidPath%\java
javac -cp AXmlResourceParser.jar;jdom-2.0.2.jar PlatformChange.java
@echo 正在进行厂商文件处理...
@echo.
java -cp AXmlResourceParser.jar;jdom-2.0.2.jar; PlatformChange %platform% %iremotePath%@echo.::获取配置文件的版本号,这里的配置文件不是apk本身的文件,是做的厂商数据存储文件
::开启变量延迟
setlocal enabledelayedexpansion
@echo 读取版本号
set platformPath=%iremotePath%\app\platformres\%folderName%\platform.xml
@echo %platformPath%
for /f "delims=" %%i in (%platformPath%) do (echo "%%i"|findstr "version" >nulif !errorlevel! equ 0 (set "version=%%i"goto version_goto)
)
goto assemble
:version_goto
::关闭变量延迟
setlocal disabledelayedexpansion
for /f tokens^=2^ delims^=^" %%a in ("%version%") do set "version=%%a"
echo 当前版本号为:%version%
@echo.:assemble
::打包前清空其文件夹下所有文件,防止打包不成功签名成旧版本的apk
del /q /s %iremotePath%\app\build\outputs\apk
set assemble=
cd %iremotePath%
@echo 请选择打包类型
@echo 1.Debug
@echo 2.Release
@echo 3.取消打包
choice /c 123 /m "" /d 2 /t 20
if %errorlevel%==1 goto debug
if %errorlevel%==2 goto release
if %errorlevel%==3 goto end::gradle需要jdk8支持
:debug
@echo.
set assemble=1
@echo 开始进行debug打包
CALL %bulidPath%\assemble.bat
md %bulidPath%\apk\%folderName%
copy %iremotePath%\app\build\outputs\apk\debug\app-debug.apk %bulidPath%\apk\%folderName%\app_Debug_%folderName%_%version%.apk
@echo.
@echo debug版本app_Debug_%folderName%_%version%.apk打包完毕
goto end:release
@echo.
set assemble=2
@echo 开始进行release打包
CALL %bulidPath%\assemble.bat
@echo.
@echo release版本打包完毕
goto key::签名
:key
@echo.
md %bulidPath%\apk\%folderName%
::签名后的apk地址
set apkname=%bulidPath%\apk\%folderName%\app_%folderName%_%version%.apk
::未签名APK路径
set apkSigned=%iremotePath%\app\build\outputs\release\apk\app-release-unsigned.apk
::密钥
set key=%iremotePath%\app\AndroidappKey.jks
::密码
set password=123456
::别名
set keystore=appecho 签名信息
echo 签名后的apk地址:%apkname%
echo 未签名APK路径:%apkSigned%
echo 密钥文件地址:%key%
echo 密钥密码:%password%
echo 别名:%keystore%
echo.
echo 正在进行apk签名...
::签名
::jarsigner打包需要jdk7支持
::jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore [你的keystore] -storepass [keystore的密码] -signedjar [签名后的apk] [未签名的apk] [keystore的别名]
jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore %key% -storepass %password% -signedjar %apkname% %apkSigned% %keystore%
echo.
echo 签名完成
goto end:end
echo.
if %platform%==1 echo 百度版本打包完毕
if %platform%==2 echo 谷歌版本打包完毕
echo.
pause:: 冒号后紧跟一个非字母数字的一个特殊符号,goto无法识别的标号,可以起到注释作用
:: UTF-8格式会出现英文乱码,要ANSI 格式
assemble.bat
@echo off
if "%assemble%"=="1" goto debug
if "%assemble%"=="2" goto release:debug
gradle assembleDebug:release
gradle assembleRelease
处理厂商文件的java源码
PlatformChange.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.Scanner;import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.xml.sax.InputSource;public class PlatformChange {static String platform;//厂商static String iremotePath;//工程地址static String version;//版本static String platforPackage;//厂商包名static String jpushkey;//推送的appkeystatic String folderName;public static void main(String[] args) {platform = args[0];//厂商iremotePath = args[1];//工程地址System.out.println("厂商" + platform);System.out.println("工程地址:" + iremotePath);System.out.println("读取版本信息文件");readPlatformXml();System.out.println("处理AndroidManifest版本信息");changeAndroidManifest();String oldPath = iremotePath + "\\app\\platformres\\" + folderName + "\\res";String newPath = iremotePath + "\\app\\src\\main\\res";System.out.println("厂家文件夹替换");copyFolder(oldPath,newPath);//修改build.gradle包名System.out.println("处理build.gradle包名");changeBuild();}/*** 读取版本信息*/public static void readPlatformXml(){if("1".equals(platform)){folderName = "baidu";}else if("2".equals(platform)){folderName = "google";}boolean isChange = false;String platformXmlPath = iremotePath + "\\app\\platformres\\" + folderName + "\\platform.xml";//厂商文件SAXBuilder builder = new SAXBuilder();Document document = null;try{InputStreamReader isr = new InputStreamReader(new FileInputStream(platformXmlPath), "UTF-8");InputSource is = new InputSource(isr);document = builder.build(is);}catch (Exception e) {e.printStackTrace();}Scanner scanner = new Scanner(System.in);Element data = document.getRootElement();//根节点-->manifestAttribute platforPackageAttr = data.getAttribute("package");Attribute versionAttr = data.getAttribute("version");if(platforPackageAttr == null){System.out.println("厂商" + folderName + "包名为空,请输入包名");platforPackage = scanner.next();data.setAttribute("package",platforPackage);isChange = true;}else{platforPackage = platforPackageAttr.getValue();}if(versionAttr == null){System.out.println("厂商" + folderName + "版本号为空,请输入版本号,格式:(1.0.00)");version = scanner.next();data.setAttribute("version",version);isChange = true;}else{version = versionAttr.getValue();System.out.println();System.out.println("当前app版本的版本号:" + version + ",是否需要修改,y为修改,任意键不修改");String str = scanner.next();if("y".equalsIgnoreCase(str)){while (true) {System.out.println("请输入新的版本号,格式:(1.0.00)");String versionStr = scanner.next();if(versionStr.matches("[0-9].[0].[0-9]{2}")){version = versionStr;data.setAttribute("version",version);isChange = true;break;}else if("n".equalsIgnoreCase(versionStr)){break;}System.out.println("格式有误,请重新输入,输入n退出");}isChange = true;}}if(isChange){try {System.out.println("readPlatformXml:" + platformXmlPath);doc2XML(document,platformXmlPath);} catch (Exception e) {e.printStackTrace();}}}public static void changeAndroidManifest(){String AndroidManifestPath = iremotePath + "\\app\\src\\main\\AndroidManifest.xml";//AndroidManifest文件地址SAXBuilder builder = new SAXBuilder();Document document = null;try{InputStreamReader isr = new InputStreamReader(new FileInputStream(AndroidManifestPath), "UTF-8");InputSource is = new InputSource(isr);document = builder.build(is);}catch (Exception e) {e.printStackTrace();}Element manifestElem = document.getRootElement();//根节点-->manifestmanifestElem.setAttribute("android:versionName",version);//APP版本manifestElem.setAttribute("android:versionCode",version.replace(".", ""));//APP版本Element permissionElem = manifestElem.getChild("permission");permissionElem.setAttribute("android:name",platforPackage + ".permission.JPUSH_MESSAGE");List<Element> usesPermissions = manifestElem.getChildren("uses-permission");//子节点集合for(Element elem : usesPermissions){String nameEle = elem.getAttribute("android:name").getValue();if(nameEle.indexOf(".permission.JPUSH_MESSAGE") > 0){elem.setAttribute("android:name",platforPackage + ".permission.JPUSH_MESSAGE");}}try {doc2XML(document,AndroidManifestPath);} catch (Exception e) {e.printStackTrace();}}/** * DOCUMENT输出XML * * @param doc JDOM* @param filePath 输出的地址* @throws Exception */ public static void doc2XML(Document doc, String filePath) throws Exception{Format format = Format.getCompactFormat(); format.setEncoding("UTF-8"); //字符编码UTF-8 format.setIndent(" ");//setIndent是设置分隔附的意思,一般都是用空格,就是当你新节点后,自动换行并缩进,有层次感,如果这样写setIndent(""),就只有换行功能,而不会缩进了,如果写成setIndent(null),这样就即不换行也不缩进,全部以一行显示了,默认的就是这样的效果,不好看。 format.setLineSeparator("\n");format.setEncodingOut(true);format.setAttributeLineSeparator(true);format.setAttributeSeparatorStr("\n");XMLOutputter outputter = new XMLOutputter(format); OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(filePath), "UTF-8"); outputter.output(doc, writer); writer.close(); } private static void changeBuild(){ String buildName = iremotePath + "\\app\\build.gradle";//build.gradle文件地址try {// read file content from fileStringBuffer content= new StringBuffer("");InputStreamReader isr = new InputStreamReader(new FileInputStream(buildName), "UTF-8");BufferedReader br = new BufferedReader(isr);String str = null;while((str = br.readLine()) != null) {if (str.trim().startsWith("applicationId")) { content.append(" applicationId \"" + platforPackage + "\""); }else{content.append(str); }content.append("\r\n"); }br.close();isr.close();Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(buildName), "UTF-8")); writer.write(content.toString()); writer.close();}catch(FileNotFoundException e) {e.printStackTrace();}catch(IOException e) {e.printStackTrace();}}/** * 复制整个文件夹内容 * @param oldPath String 原文件路径 如:c:/fqf * @param newPath String 复制后路径 如:f:/fqf/ff * @return boolean */ public static void copyFolder(String oldPath, String newPath) {try { (new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹 File a=new File(oldPath); String[] file=a.list(); File temp=null; for (int i = 0; i < file.length; i++) { if(oldPath.endsWith(File.separator)){ temp=new File(oldPath+file[i]); } else{ temp=new File(oldPath+File.separator+file[i]); } if(temp.isFile()){ FileInputStream input = new FileInputStream(temp); FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString()); byte[] b = new byte[1024 * 5]; int len; while ( (len = input.read(b)) != -1) { output.write(b, 0, len); } output.flush(); output.close(); input.close(); } if(temp.isDirectory()){//如果是子文件夹 copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]); } } } catch (Exception e) { System.out.println("复制整个文件夹内容操作出错"); e.printStackTrace(); } }
}
这里面对AndroidManifest.xml的处理我用的是jdom.jar的包。但该jar包写入”android:xxx“结构的节点内容无法修改只能新增。因此,我对jdom的源码进行修改。
jdom.jar源码及Demo地址在文章末尾。
特比说明下,gradle的环境要与项目环境一致,否则会打包apk失败。
jdom源码
http://download.csdn.net/download/feiniyan4944/10178610
Demo源码
↓↓↓↓
http://download.csdn.net/download/feiniyan4944/10178500
APP多平台快速切换相关推荐
- 如何快速制作App应用软件?国内有哪些比较好用的App制作平台?
如今,各类App让大家像淘金似往自个儿的爱机里装,无论是Apple Store还是安卓市场,应用商店总是手机控们的发烧地.但是这类门户却满足不了满脑子想法的动手一族,可惜他们只是梦想家,却不是程序猿, ...
- Unity中使用软连接快速切换平台
Unity中使用软连接快速切换平台 Unity会把所有的资源在不同平台下进行不同的设置, 且每次切换平台都需要重新计算, 在大型项目中, 由于资源很多, 切换的成本比较高, 可能动不动的就是几十分钟, ...
- 快速生成APP的平台
介绍了国内快速生成APP的平台与自己平台的对比,很有参考价值. 同类网站 安米网 http://www.appbyme.org/ 追信 http://app.zhui.cn/ 简网app工厂 http ...
- 安居客 Android App 走向平台化 | CSDN 博文精选
作者 | 张磊 责编 | 屠敏 出品 | CSDN博客 安居客 Android App 距离上次的模块化/组件化重构已经两年多了,重构之后很好的支撑了两年多以来的业务发展.但这个世界总是在向前走的,没 ...
- # 飞书APP集成平台-数字化落地
飞书APP集成平台-数字化落地 1. 多维表格助力项目管理 2. 看版视图-实现数据分类整理与可视化 3 三一重工"灯塔工厂"的数字化三个阶段 4. 伯镭科技的绿色智慧矿山无人驾驶 ...
- 安居客 Android App 走向平台化
首发于微信公众号:BaronTalk 安居客 Android App 距离上次的模块化/组件化重构已经两年多了,重构之后很好的支撑了两年多以来的业务发展.但这个世界总是在向前走的,没有任何一种架构能够 ...
- 安居客 Android APP 走向平台化 | 开发者说·DTalk
本文原作者: 张磊BARON,原文发布于微信公众号: BaronTalk https://mp.weixin.qq.com/s/71VfmQ5ZyihgTwosMPbSmw 安居客 Android ...
- 开发安卓app游戏_游戏陪玩系统APP开发平台
点击上方蓝字关注我们 游戏陪玩系统开发,找[金生:157-6875-2419微电],游戏陪玩系统定制开发平台,游戏陪玩系统开发模式,游戏陪玩系统APP开发平台 游戏陪玩软件开发 游戏陪玩系统源码搭建平 ...
- 源码推荐:仿写映客直播 ,快速切换主题 ,星星评分控件,表格样式,可以横向移动的表格, 仿微信键盘-
仿写映客直播(上传者:五仁月饼) 工作之余写的,基于IJKPlayer播放,对内存做了处理.目前已完成直播列表和直播间的搭建,后续还会慢慢完善. 项目地址 publishImageAndVideoAn ...
最新文章
- 安装caffe(CPU版本)的一些参考和问题的解决
- 如果计算机用户有密码 待机,电脑待机密码怎么设置
- [蓝桥杯2019初赛]完全二叉树的权值-完全二叉树的性质
- 使用Python爬虫爬取网络美女图片
- ×××数据库导数据ora-01400错误小计
- 调整手机titlebar与app的titlebar相衔接
- Java基础之如何修改字符串?
- html%3c转译,[转]URL编码
- Pascal voc 数据集下载网址
- jQuery图片LightBox插件 点击图片放大 支持移动手机
- ADS 修改版图默认单位
- 周礼键君:中国福建省建瓯市之《闽郡八音字典》
- 一些思考:腾讯股价为何持续都低
- Python turtle画图之心形图案
- 判断浏览器必须是IE10以上,低于IE10做出提示
- 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
- 摄像头在线测试_Leez学院| 面部检测 精准可靠 Leez P515 OpenCV工程测试
- shell 文件处理 并集 交集 差集
- ROS:服务数据(srv)的定义与使用
- SQL每日一题(20201218)来查找与之前(昨天的)日期相比温度更高的所有日期
热门文章
- 解决webpack打包css时CssSyntaxError的问题
- 多多客id是什么意思_【多多情报学堂】拼多多id是什么?拼多多店铺id在哪里看?...
- 微波技术大作业课设-分立电容电感+微带单枝短截线+微带双枝短截线
- 海南大学信号与系统838报考高频问题整理(五)
- 台式电脑脑计算机没法启动怎么办,台式机主机电源灯不亮,开不了机怎么办? 台式电脑无法开机什么原因...
- (转载)解决FileOutputStream中文乱码问题
- xdm linux,XDM (简体中文)
- GBase XDM 数据库ldapdelete命令讲解和示例分析
- Java中为按钮添加监听器(事件处理)四种形式总结
- java word合并单元格_java使用freemarker模板导出word(带有合并单元格)文档