2019独角兽企业重金招聘Python工程师标准>>>

一.应用的打包签名

1.打包是什么?

打包就是根据签名和其他的标识生成安装包

2.签名是什么?

1.在android应用文件(apk)中保存的一个特别字符串
2.用来标识不同的应用开发者:开发者A,开发者B
3.一个应用开发者开发的多款应用使用同一个签名
> 就好比是一个人写文章,签名就相当于作者的署名。
> 如果两个应用都是一个开发者开发的,那么签名就是一样的。
> 这个开发者,可以是个人,也可以是公司、团体。

3.为什么要使用签名?

原因1:最简单直接的回答: 系统要求的。
>Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,是没有办法安装到系统中的!
原因2:
不同程序员开发的应用包名可能会相同, 导致一个应用覆盖掉另一个应用。
> 如果只有包名的概念,那么如果B应用与已经安装的A应用包名一样,那就实现覆盖。不合理!
> 而事实上是装不上B的,它会提示,存在包名一致,但是签名不一样的。这就不会覆盖。

4.如何为APK签名?

1.)用来生成应用签名的文件

一般我们在androidStudio运行的是采用的默认的debug.keystore

Eclipse生成的是xxxx.keystore

androidstudio生成的是xxxx.jks

2.)打包自己签名APK文件(我们这里采用的AndroidStudio)步骤:

Build-->Generate Signed APK如下图所示:

如果没有key store文件,那就创建文件

> 这里指定一个文件名。注意:在as中,签名文件keystore类型的文件变为jks格式的文件。
> 这里输入的是表明是谁,不适合写一个包名。

> 上面的密码是用来访问最上面的path路径文件的密码。而最上面的文件用来生成一个签名字符串。
> 下面Alias是一个别名。接下来的密码:是用来生成一个签名的时候,还需要的一个密码。与上面的密码可以不一致。
> 再下面的25,指的是有效期。google应用市场规定应用的有效期不低于25年。还可以改为100年。也就是说100年以后,我们的xxx.jks签名文件就失效了。

> 指明生成的apk的位置,Build Type:release:发布版 debug:测试版。
> 点击finish,稍等一会

> 默认在As工程中bin下生成的apk文件也有签名。只是用到了debug_keystore(测试)的模式。而我们想发布到应用市场的话,那就需要我们自己提供一个签名,不能用默认的了,不合适。如下:

3.)在代码中获得应用签名

public void getSingInfo() {try {PackageInfo packageInfo = getPackageManager().getPackageInfo("com.atguigu.p2p", PackageManager.GET_SIGNATURES);Signature[] signs = packageInfo.signatures;Signature sign = signs[0];parseSignature(sign.toByteArray());} catch (Exception e) {e.printStackTrace();}
}
public void parseSignature(byte[] signature) {try {CertificateFactory certFactory = CertificateFactory.getInstance("X.509");X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature));String pubKey = cert.getPublicKey().toString();String signNumber = cert.getSerialNumber().toString();
//发布的key和版本号Log.e("TAG", "pubKey:" + pubKey);Log.e("TAG", "signNumber:" + signNumber);} catch (Exception e) {e.printStackTrace();}
}

4.)使用签名文件时我们应该注意的几个方面:

千万不要把xxxx.keystore/xxxx.jks文件搞丢了

假说如果搞丢了:当APK版本升级时,用户必须首先撤除APK,在安装。否则直接安装会失败。

举例个使用场景:
公司程序员A写的应用,然后走了。后来来了一个程序员B把应用更新以后,又重新打包发布,使用的签名不一致。那完了。
导致出现更新不了应用的情况。必须把应用卸载了才能重新装。那想象一下,如果一个20万用户的应用,在更新时,发现安装不了。那可能随后就卸载了。或者就不更新了。
另外还影响的是:应用市场有下载量排名,如果重新签名,那就得重头来算。

5.)打包过程中遇到问题怎么解决?

现象:
Android导出APK包时出现,编译调试时不会出现。
错误信息:
Error:(16) Error: "baidutieba_client_inavailable" is not translated in "en" (English) [MissingTranslation]
Error:(63) Error: "baidutieba" is not translated in "en" (English) [MissingTranslation]
Error:(67) Error: "share_to_baidutieba" is not translated in "en" (English) [MissingTranslation]
错误截图:

解决办法:
resources 标签内增加两个属性即可:
<?xml version="1.0" encoding="utf-8" ?>  
<resources xmlns:tools="http://schemas.android.com/tools"  
  tools:ignore="MissingTranslation">  
</resources>

二.友盟的多渠道打包

1.)原理的说明:

1.什么是多渠道包?
渠道包就是要在安装包中添加渠道信息,也就是channel,对应不同的渠道,例如:小米市场、360市场、应用宝市场等
2.为什么要提供多渠道包?
我们要在安装包中添加不同的标识,应用在请求网络的时候携带渠道信息,方便后台做运营统计(这就是添加渠道信息的用处)。
3.实现多渠道打包的原理:
一般来讲,这个渠道的标识会放在AndroidManifest.xml的Application的一个Metadata中。然后就可以在java中通过API获取对应的数据了。
 
4.如何实现?
现在android渠道多种多样,其实渠道不仅仅局限于应用市场,一种推广方式也可以看做一个渠道,比如:通过人拉人的方式去推广,官网上推广,百度推广等。所以说渠道成千上万,为了推广,有时候一次也会打成千的安装包,那你半天或者一天啥都别干了,所以介绍几个大公司高效的打包方式,借鉴一下。
 
第一种:友盟就提供了多渠道打包的方式,可用于渠道统计等。
现在Android的构建工具换成了gradle,通过gradle,简单配置后就可以实现自动打所有渠道包。

2.)友盟打包的步骤:

1.首先去友盟的官网去注册,申请APP KEY

2.按照umeng的要求,manifest文件中需要有

<meta-dataandroid:name="UMENG_CHANNEL"android:value="${UMENG_CHANNEL_VALUE}" />

这段配置,value那里就是wandoujia,360之类的渠道名称,但是我们在这里不会去写渠道名,写的是一个占位符,后面gradle编译的时候会动态的替换掉它。

3.在module(一般也就是app)的build.gradle的android{}中添加如下内容:

productFlavors{wandoujia{manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]}xiaomi{manifestPlaceholders=[UMENG_CHANNEL_VALUE: "xiaomi"]}}

productFlavors是android节点的一个自节点。你需要打什么渠道的包,就在这里按umeng的要求用渠道名给UMENG_CHANNEL_VALUE赋值。

4.优化1:上面只是两个渠道,如果有几十个渠道,都这样写,重复的东西太多,观察到每个渠道就是flavor的名称,所以修改如下:

productFlavors{wandoujia{//manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]}xiaomi{//manifestPlaceholders=[UMENG_CHANNEL_VALUE: "xiaomi"]}}productFlavors.all { flavor ->flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]}

5.优化2:上面经过签名打包后生成的apk的名称是有默认命名规则的,如:xxx-xiaomi-release.apk 但是我们想包含版本信息如:xxx-xiaomi-release-1.0.apk,所以最终打包脚本如下:

productFlavors{wandoujia{//manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]}xiaomi{//manifestPlaceholders=[UMENG_CHANNEL_VALUE: "xiaomi"]}}productFlavors.all { flavor ->flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]}applicationVariants.all { variant ->variant.outputs.each { output ->def outputFile = output.outputFileif (outputFile != null && outputFile.name.endsWith('.apk')) {def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}.apk")output.outputFile = new File(outputFile.parent, fileName)}}}

5.获取渠道

在代码中我们可以通过读取mate-data信息来获取渠道,然后添加到请求参数中,获取方法如下:

private String getChannel() {try {PackageManager pm = getPackageManager();ApplicationInfo appInfo = pm.getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);return appInfo.metaData.getString("UMENG_CHANNEL");} catch (PackageManager.NameNotFoundException ignored) {}return "";
}

6.执行签名打包:

这时候你去app/build/outputs/apk中就能看到自动打好的渠道包了。

3.美团多渠道打包

1.)原理:把一个Android应用包当作zip文件包进行解压,然后发现在签名生成的目录下(META-INF)添加一个空文件不需要重新签名。利用这个机制,该文件的文件名就是渠道名。这种方式不需要重新签名等步骤,非常高效。

2.)美团打包的步骤:

下载python工具包

1、将要打包的apk放到PythonTool中
2、在PythonTool/info/channel.txt中写入需要的渠道,一个渠道占一行
3、双击执行PythonTool/MultiChannelBuildTool.py文件(需要Python环境),就会生成渠道包
4、获取渠道信息:将JavaUtil文件中的ChannelUtil.java拷贝到工程,调用ChannelUtil.getChannel即可获取渠道

3.)用Java代码获取多渠道信息

package com.czt.util;import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceManager;
import android.text.TextUtils;public class ChannelUtil {private static final String CHANNEL_KEY = "cztchannel";private static final String CHANNEL_VERSION_KEY = "cztchannel_version";private static String mChannel;/*** 返回市场。  如果获取失败返回""* @param context* @return*/public static String getChannel(Context context){return getChannel(context, "");}/*** 返回市场。  如果获取失败返回defaultChannel* @param context* @param defaultChannel* @return*/public static String getChannel(Context context, String defaultChannel) {//内存中获取if(!TextUtils.isEmpty(mChannel)){return mChannel;}//sp中获取mChannel = getChannelBySharedPreferences(context);if(!TextUtils.isEmpty(mChannel)){return mChannel;}//从apk中获取mChannel = getChannelFromApk(context, CHANNEL_KEY);if(!TextUtils.isEmpty(mChannel)){//保存sp中备用saveChannelBySharedPreferences(context, mChannel);return mChannel;}//全部获取失败return defaultChannel;}/*** 从apk中获取版本信息* @param context* @param channelKey* @return*/private static String getChannelFromApk(Context context, String channelKey) {//从apk包中获取ApplicationInfo appinfo = context.getApplicationInfo();String sourceDir = appinfo.sourceDir;//默认放在meta-inf/里, 所以需要再拼接一下String key = "META-INF/" + channelKey;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();if (entryName.startsWith(key)) {ret = entryName;break;}}} catch (IOException e) {e.printStackTrace();} finally {if (zipfile != null) {try {zipfile.close();} catch (IOException e) {e.printStackTrace();}}}String[] split = ret.split("_");String channel = "";if (split != null && split.length >= 2) {channel = ret.substring(split[0].length() + 1);}return channel;}/*** 本地保存channel & 对应版本号* @param context* @param channel*/private static void saveChannelBySharedPreferences(Context context, String channel){SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);Editor editor = sp.edit();editor.putString(CHANNEL_KEY, channel);editor.putInt(CHANNEL_VERSION_KEY, getVersionCode(context));editor.commit();}/*** 从sp中获取channel* @param context* @return 为空表示获取异常、sp中的值已经失效、sp中没有此值*/private static String getChannelBySharedPreferences(Context context){SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);int currentVersionCode = getVersionCode(context);if(currentVersionCode == -1){//获取错误return "";}int versionCodeSaved = sp.getInt(CHANNEL_VERSION_KEY, -1);if(versionCodeSaved == -1){//本地没有存储的channel对应的版本号//第一次使用  或者 原先存储版本号异常return "";}if(currentVersionCode != versionCodeSaved){return "";}return sp.getString(CHANNEL_KEY, "");}/*** 从包信息中获取版本号* @param context* @return*/private static int getVersionCode(Context context){try{return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;}catch(NameNotFoundException e) {e.printStackTrace();}return -1;}
}

4.)美团打包的优缺点

优点:
这种打包方式速度非常快,900多个渠道不到一分钟就能打完
 
缺点:
1、google如果哪天更改打包规则,使得在META-INF中建立空文件还需要重新打包,这种方式将不可用
 
2、一些不法的渠道商很容易通过工具修改渠道,如果一个渠道商,通过网络劫持和篡改渠道的组合方式来获取暴利,对于程序开发者来说可能会存在着巨大的经济损失

4.360多渠道打包

1.)原理:

apk文件本质就是zip文件,利用zip文件“可以添加comment(摘要)”的数据结构特点,在文件的末尾写入任意数据,而不用重新解压zip文件,我们就可以将渠道信息写入摘要区

2.)打包的步骤

1、将要写入渠道信息的apk放入MCPTool文件夹中
2、修改MCPTool.bat批处理文件,更改渠道和密码(渠道信息为了安全需要加密)
 
3、将apk拖到MCPTool.bat上执行,将会生成渠道包
 
4、修改MCPTool-check.bat中的密码和MCPTool.bat中的密码一致
 
5、将渠道包拖到MCPTool-check.bat上执行,就可以检查渠道信息是否正确
 
6、获取渠道:将MCPTool.java添加到工程或者将MCPTool.jar导入工程,调用MCPTool.getChannelId(this,"12345678","") 第一个参数为context,第二个是密码,第三个是默认值

注意点:在使用工具360打包时,出现了如下问题:

C:\ProgramData\Oracle\Java\javapath\java.exe找不到,原因是可能系统自己查找时默认了C:\ProgramData\Oracle\Java\javapath下的java.exe,解决的思路是将%JAVA_HOME\bin放在path路径的最前面就可以解决。

3.)优缺点:

优点:

1、5M的apk,1秒种能打300个
2、在下载apk的同时,服务端可以写入一些信息,例如邀请码,分享信息等
 
缺点:
渠道信息也是很容易修改,虽然可以加密,只是提高了修改的门槛

转载于:https://my.oschina.net/quguangle/blog/917100

APK打包的详细说明相关推荐

  1. Android反编译apk修改版本号重新打包签名详细教程(超详细)

    文章目录 一.反编译工具介绍 1:apktool 获取资源文件 2:dex2jar(源码文件获取) 3:jd-gui 查看APK中classes.dex转化成出的jar文件,即源码文件 二.apkto ...

  2. 安卓逆向_1 --- 逆向环境配置、APK 文件结构、APK 打包流程

    哔哩哔哩:https://www.bilibili.com/video/BV1UE411A7rW?p=1 Android 逆向工程师系统培训‹第九期›( 课程目录 ):https://ke.yijin ...

  3. Android 应用apk打包原理

    文章目录 前言 一.打包前 - app源码结构 二.打包后 - apk 文件结构 - apk结构? - 图示 (1) - 图示 (2) 三.那是怎么生成的? 1.apk 打包流程 2.详解:构建流程中 ...

  4. 【朝花夕拾】Android性能篇之(四)Apk打包

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/9721337.html],谢谢! APK,即Android Package,是将android程 ...

  5. android Apk打包过程概述_android是如何打包apk的

    最近看了老罗分析android资源管理和apk打包流程的博客,参考其他一些资料,做了一下整理,脱离繁琐的打包细节和数据结构,从整体上概述了apk打包的整个流程. 流程概述: 1.打包资源文件,生成R. ...

  6. android-xBuild apk差分与合成,zip差分与合成,lua打包,apk打包,png/jpg图片压缩

    android-xBuild 是一项集成了apk差分与合成,zip差分与合成,lua打包,apk打包,png/jpg图片压缩五大功能的开源项目 (github地址:https://github.com ...

  7. 【Android 安装包优化】APK 打包流程 ( 文件结构 | 打包流程 | 安装流程 | 安卓虚拟机 )

    文章目录 一.APK 文件结构 二.APK 打包流程 三.APK 安装流程 四.安卓虚拟机 一.APK 文件结构 Android 应用的安装包时 以 " .apk " 为后缀的 A ...

  8. 【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )

    文章目录 一.动态库打包配置 二.NDK 完整配置参考 三.参考资料 一.动态库打包配置 在 build.gradle 构建脚本中 , 配置 ndk 编译的动态库 CPU 架构类型 ; 在 " ...

  9. 【错误记录】Android Studio 导入外部 so 动态库报错 ( java.lang.UnsatisfiedLinkError | 指定 APK 打包动态库的 CPU 架构 )

    文章目录 一.报错信息 二.解决方案 ( 指定 APK 打包动态库的 CPU 架构 ) 一.报错信息 外部引用 so 动态库 , 如果只有一个 armeabi-v7a 的动态库 , 那么如果在 arm ...

最新文章

  1. detectmultiscale函数参数含义_OpenCV detectMultiScale函数
  2. 用php对文件的操作
  3. 用户相关的文件、解析以及命令的使用
  4. 支付系统整体架构详解
  5. java 区块链使用_使用Java创建第一个区块链
  6. Python标准库的强大功能的相关介绍
  7. js 拼接html 表格,js合并table单元格(拼table的时候并不知道具体几行几列)
  8. HDU2855—Fibonacci Check-up
  9. 字符串和字符数组的关系
  10. 安全强化你的 Linux 服务器的七个步骤
  11. opencv +opencv_contrib+CMake+VS2015
  12. [转]Flex 中的皮肤
  13. 打开的文件过多问题排查思路及解决过程
  14. 用matlab绘制对数图像,matlab图像绘制(进阶篇)
  15. 搭建-ico图标制作
  16. DSP-BIOS使用入门
  17. 华为笔记本键盘说明图_没有键盘的笔记本:华为 MateBook上手图赏
  18. python报错: arry[i] = t IndexError: list assignment index out of range
  19. fatal: unable to access ‘https://github.com/xxx/123.git/‘: Failed connect to github.com:443 解决方案
  20. python火柴人游戏代码_Python小游戏 Hangman

热门文章

  1. python编程控制机器人_基于Python开发的微信图灵机器人
  2. 高通平台开发系列讲解(USB篇)USB端口的说明及切换方法
  3. 区块链架构与交易流程(fabric1.0)
  4. 用灌水法解NOIP2017提高组D2第一题:奶酪
  5. 雍禾医疗上市的喜和忧:获80倍超额认购,利润开始下滑,成本高企
  6. 北京周边自行车骑行线路大全
  7. 三星 N9006 note3 成功root
  8. 安装MySql时初始化 MySQL 数据库失败的几个总结
  9. js滚动到指定位置显示或隐藏元素
  10. mybatis实现一对多有几种方式_两件塑胶件连接,有哪几种方式实现?