全民k欹中lol怎么看收到的礼物礼物在那

百度知道 - 信息提示
知道宝贝找不到问题了&_&!!
该问题可能已经失效。
秒以后自动返回西西软件下载最安全的下载网站、值得信赖的软件下载站!
→ 全民K歌清唱在哪里
全民K歌清唱方法介绍
v3.3.8 官方最新版
类型:运动养生大小:51.5M语言:中文 评分:6.5
是一款非常好用手机K歌应用软件,你可以使用全民K歌录制歌曲,当然你也可以进行清唱更好的展示自己的歌唱能力哦,不过一些朋友对全民k歌清唱功能不是很熟悉,那么全民K歌清唱在哪里,下面小编就给大家带来全民K歌清唱方法介绍。全民K歌官方最新版:1、打开全民K歌主页,点击清唱。2、点击箭头所指的位置,就可以开始录制啦(必须录满30秒才能结束哦)3、给你的清唱加上混响和变音点击发布就ok啦。全民K歌清唱有杂音怎么办你在进行清唱的时候尽量让嘴靠近你的麦,而且最好带耳机进行清唱这就是小编给大家带来的全民K歌清唱相关介绍了,希望对大家有用。
西西软件园提供最好用的歌软件帮助各位音乐爱好者练习唱歌,海量的歌曲库,超强的练唱图谱功能,最新点唱榜单,带给你全新的歌体验,歌软件都很小巧,操作简捷功能强大.如果大家看过浙江卫视的我爱记歌词,里面有个软件系统跟我们的软件非常的相似哦,有评分标准,还有线谱,非常的牛.....
10-22 / 10.9M
推荐理由:呱呱K歌伴侣是一款专业的音乐K歌软件,拥有数十万首歌曲、同步歌词、卡拉OK效果以及多种独特的音频特效,完
05-15 / 14.1M
推荐理由:酷我K歌是一款K歌必备的在线唱歌软件,海量的卡拉OK曲库,超强的练唱图谱功能,最新KTV点唱榜单,让你足不出
08-16 / 42.7M
推荐理由:&爱唱久久k歌软件
爱唱久久,喜欢在网上k歌的朋友一定不会感到陌生
中国最大的网络K歌社区之一
10-16 / 30.4M
推荐理由:KBOX(原虚拟视频)一款集音乐播放、练唱、虚拟视频等功能于一体的K歌软件,歌曲想听就听,想练就练,视频要
10-13 / 103.1M
推荐理由:主要用于网络K歌,支持创新5.1、7.1,创新外置声卡、1095以及其他的专业音频声卡。前提是电脑有独
07-12 / 17.4M
推荐理由:家族徽标1 个性家族徽标,跟促进团队成员亲密关系的建立。我们是一个集体,共同迎接每一个挑战。闪耀等级,
09-0809-0609-0602-2610-1210-1209-0309-0209-0206-07
阅读本文后您有什么感想? 已有23人给出评价!
名称大小下载发帖人是女婴父亲,刚以难民身份进入德国。
经过铁路菜市的火车速度很慢,很远就要鸣笛示意。
声明:本文由入驻搜狐公众平台的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
  深圳新闻网福田讯 (记者 吴英敏 通讯员 付自虎)9月1日晚,2016深圳全民K歌大赛开幕演唱会在深圳著名音乐LIVE HOUSE本色酒吧激情开唱,2015年全民K歌大赛10强选手为大家献上了一台精彩的演唱秀。由此,也正式拉开了2016深圳第二届全民K歌大赛和深圳首届长者卡拉OK大赛的序幕。
  赛事是由中共深圳市福田区委宣传部(区文化体育局)、深圳市福田区公共文体发展中心、共青团深圳市福田区委员会共同主办,福田区娱乐行业协会、福田区文化馆&音乐主题馆联合承办,受福田区宣传文体事业发展专项资金资助的大型公益群众性歌唱类赛事。活动旨在“寻找身边最会唱歌的普通人”,为深圳喜爱唱歌的市民朋友提供一个展示交流的平台,拉动深圳文化消费。
  免费参赛赢众多好礼,冠军奖励5万元
  作为公益性活动,两项赛事均不收取任何报名费,所有奖励由福田区娱乐行业协会自筹。全民K歌大赛面向18周岁至49周岁中青年朋友,冠军奖励3万元现金,2万元现金券,2.8万元合纵音乐学院奖学金。10强选手举行1场专场演唱会,提供2次公开演出机会;特别优秀歌手,提供驻场演出工作合约、与明星同台机会。另外,各KTV分赛场对在其场所参赛的选手提供了众多好礼,有的参赛就送免费练歌券,有的参赛就送现金券、水杯等,有的额外增加奖励,如福永皇家永利KTV分赛场对于在其场所晋级决赛及获得冠亚季军的,另外再奖励1000元~10000元不等的现金。
  首届长者卡拉OK大赛,面向50岁以上长者,不分一二三等奖,奖励前10名,授予“十大长者歌手”荣誉称号,每人奖励现金3000元,现金券1000元,举行1次专场演唱会。
  3个月88场比赛,打造深圳最大规模群众歌唱赛事
  自9月1日起,至12月10日结束,两项比赛历时近3个月,将在深圳掀起一阵“K歌热潮”。两项比赛均分为海选、初赛、复赛、决赛四个阶段,海选共举行3次,在所有KTV分赛场同时举行,参赛者有3次机会参与比赛。全民K歌大赛预计举行62场比赛,长者卡拉OK大赛预计举行26场赛事,88场比赛,将是深圳“史上最大规模”群众性歌唱赛事。2015年,深圳首届全民K歌大赛参赛选手达3390人次。
  15个分赛场覆盖全市,市民可就近参赛
  本次全民K歌大赛,分赛区除福田外,还有罗湖、南山、宝安、龙岗、龙华新区,6个区共设立14个KTV分赛场。另外,组委会与腾讯合作,在腾讯手机KTV平台 “全民K歌”设立了海选分赛场,参赛者可直接在平台上录歌参赛,选取优秀者在线下KTV进行初赛。各分赛场对于参赛者均有优惠或赠礼,市民朋友可以就近选择合适分赛场参赛。
  系列活动同时举办,赛前培训练歌服务周到
  两项比赛均为福田区政府民生实事“2016福田公益练歌房”的主要内容。“福田公益练歌房”系列文化惠民活动是由政府与协会合作,整合KTV资源,通过“政府补一点、企业让一点、市民出一点”的方式,为辖区居民提供免费与优惠的学歌、练歌、赛歌、录歌服务的公益文化服务。活动主要包括“午后10元唱”、“全民K歌大赛”、“长者卡拉OK大赛”、“免费K歌指导”、“唱K有礼”等5大板块。为了使参赛者取得好成绩,通过参赛提升歌唱技能,组委会将邀请专业声乐教师,对所有参赛者免费提供赛前培训,所有参赛选手,均可参与“午后10元唱”活动,花10元练歌6小时。
  多项措施确保公平公正
  为了保证公平公平,组委会采取了多项措施。一是从参赛对象上进行明确区别,将长者与中青年人进行区分,保证长者朋友公平参赛;二是从唱法上进行限制,考虑到市民群众都未接受专业声乐教育,无法与专业歌手进行PK,第二届全民K歌大赛要求限流行唱法;而长者主要唱民歌,长者卡拉大赛则可以自由选择流行唱法、民族唱法、美声唱法;三是评委权威。本次全民K歌大赛评委会主任陈小奇、长者卡拉OK大赛评委会主任熊家源,均是我国声乐界的知名“大咖”,他们确保了赛事评判的权威性;四是注意保密。所有分赛场,均由组委会随机指派评委,且在开赛前1天予以确定。所有评委,不得在同一分赛场担任评委。组委会希望通过以上多项措施,力求做到公平公正。
  两项比赛,市民关注“娱乐在手”微信公众号,即可报名。长者卡拉OK大赛亦可通过福田区各社区老年协会报名。9月11日将举行第一次海选。
欢迎举报抄袭、转载、暴力色情及含有欺诈和虚假信息的不良文章。
请先登录再操作
请先登录再操作
微信扫一扫分享至朋友圈
搜狐公众平台官方账号
生活时尚&搭配博主 /生活时尚自媒体 /时尚类书籍作者
搜狐网教育频道官方账号
全球最大华文占星网站-专业研究星座命理及测算服务机构
深圳新闻网是由国务院新闻办批准,由广东省委宣传部、深圳市委...
73250文章数
主演:黄晓明/陈乔恩/乔任梁/谢君豪/吕佳容/戚迹
主演:陈晓/陈妍希/张馨予/杨明娜/毛晓彤/孙耀琦
主演:陈键锋/李依晓/张迪/郑亦桐/张明明/何彦霓
主演:尚格?云顿/乔?弗拉尼甘/Bianca Bree
主演:艾斯?库珀/ 查宁?塔图姆/ 乔纳?希尔
baby14岁写真曝光
李冰冰向成龙撒娇争宠
李湘遭闺蜜曝光旧爱
美女模特教老板走秀
曝搬砖男神奇葩择偶观
柳岩被迫成赚钱工具
大屁小P虐心恋
匆匆那年大结局
乔杉遭粉丝骚扰
男闺蜜的尴尬初夜
客服热线:86-10-
客服邮箱:全民 K 歌增量升级方案 - 推酷
全民 K 歌增量升级方案
本文主要介绍一种增量升级方案。用户在升级版本时,不需要下载完整的安装包,只需下载增加的部分即可体验新版本完整功能,即节约用户流量,也减少服务器流量,并解决了多渠道问题,值得尝试。
随着全民K歌版本不断迭代,安装包大小也不断增大,现在每次版本更新,用户都需要下载最新版本安装包,如果使用增量更新的方式,用户每次更新只下载新版本和旧版本差异的部分,将会为用户和服务器节约大量流量。以全民K歌3.2和3.3版本为例:
| 文件名 &| 文件大小 |
|———- &| ———- &|
| karaoke_3.2.apk &| 30.4M |
| karaoke_3.3.apk &| 27.6M |
| 3.2_3.3.patch & &| 7.3M &|
3.2_3.3.patch文件是3.2和3.3版本的差异部分,大小为7.3M,如果用户使用增量升级方案,相对于下载完整的3.3版本27.6M,用户将节约20.3M。下面我将介绍如何使用用户本地已安装的版本karaoke_3.2.apk + 差异包3.2_3.3.patch生成最新版本karaoke_3.3.apk。
二、实现原理
1、服务器端:
2、客户端:
增量更新的原理是将旧版本的apk和新版本的apk进行二进制对比,得到差异包,用户升级更新时,根据本地版本从服务器下载需要的差分包,使用本地版本+差分包生成新版apk。而差异包需要提前由服务器生成,用户在升级时,服务器根据用户当前版本下发差异包。列如:用户从全民K歌3.2版本升级到3.3版本,需要从服务器下载差异包(3.2_3.3.patch),再使用用户正在使用的全民K歌3.2版本apk(karaoke_3.2.apk),即可生成全民K歌3.3版本(karaoke_3.3.apk)。
三、实现步骤
1、生成差异包
apk文件的差分和合并都是使用的开源的二进制比较工具 bsdiff 实现。下载的bsdiff-4.3版本中有几个文件,其中bsdiff.c用于生成差异包的源码,bspatch.c用于合成apk的源码,makefile是生成可执行文件的脚本。亲测在linux系统中,执行makefile文件,可生成一个bsdiff工具,使用该工具即可生成差异包。
在服务器端使用bsdiff工具生成差异包。其中karaoke_3.2.apk和karaoke_3.3.apk是我们的老版本和新版本安装包(都未写入渠道号)。在命令行执行./bsdiff karaoke_3.2.apk karaoke_3.3.apk 3.2_3.3.patch 命令即可生成差异包3.2_3.3.patch。
2、解决多渠道问题
(1)多渠道说明
多渠道是指根据不同的市场打不同的安装包包,比如应用宝,安卓市场,百度市场,Google市场,360市场等等。分渠道打包目的是为了针对不同市场做出不同的一些统计,数据分析,收集用户信息。多渠道的实现通常是在生成安装包的时候,把渠道号写入安装包的渠道文件中,用户在使用app时,读取安装包的渠道文件内容,并上传服务器。例如应用宝渠道,则在安装包中有一个qua.ini文件,里面内容是YYB_D,用户在使用APP时,读取qua.ini文件内容,把YYB_D上传服务器。
由实现原理可以看出,服务器端需要两个安装包对比,然后才能生成差异包。在生成安装包的时候,不同渠道的安装包内容是不一样的(文件md5值不一样),不同渠道的新老版本生成的差异包也不一样。解决这个问题比较粗暴的方案是:每个渠道都生成一个差异包,客户端合成的时候,根据用户使用的渠道安装包下载对应渠道的差异包,再合成对应渠道最新的安装包。这时如果有50个渠道,就需要50个差异包,这个方案实现复杂,不利于差异包的维护。
这里微信团队提出了另一种实现方案:把渠道号写入安装包的注释字段。该方案不会破坏安装包,经验证,android手机可以正常安装使用。Android apk安装包是zip格式文件,在zip文件的最后有一个记录说明。格式如下:
从表中可以看出,在文件的末尾有两个字段:Comment length和Comment,分别表示注释长度(2个字节)和注释内容(N个字节)。apk安装包打包完成后, Comment length默认为0,comment为空,我们可以把入渠道号写入comment字段。app启动后,读取Comment内容即可获取渠道号。
(2)安装包未写入渠道号时:
从图中可以看出,Comment length=0,说明这个安装包未写入任何注释。在使用gradle编译打包生成的apk默认是没有写入任何注释信息的。
(3)安装包写入应用宝(YYB_D)渠道号时:
从图中可以看出,Comment length=12,说明这个安装包的注释长度为12个字节。(为了方便定位渠道号,除了渠道号,在文件末尾多写了7个字节内容)12 = 5 + 2 + 5 { 5个字节渠道号(YYB_D)+ 2个字节的MAGIC字符长度说明 + 5个字节的MAGIC(!ZXK!)}。
(4)写渠道号关键代码:
// ZIP文件注释长度字段和MAGIC的字节数
static final int SHORT_LENGTH = 2;
//注释字符编码
static final String UTF_8 = &UTF-8&;
// 文件最后用于定位的MAGIC字节
static final byte[] MAGIC = new byte[]{0x21, 0x5a, 0x58, 0x4b, 0x21}; //!ZXK!
//写入渠道号
public static void writeQUA(File file, String comment) throws IOException {
byte[] data = comment.getBytes(UTF_8);
final RandomAccessFile raf = new RandomAccessFile(file, &rw&);
//定位到文件有效内容的末尾(文件长度-注释长度)
raf.seek(file.length() - SHORT_LENGTH);
//写入注释字节数{注释字节数+2(MAGIC长度说明)+MAGIC长度}
writeShort(data.length + SHORT_LENGTH + MAGIC.length, raf);
//写入注释内容
writeBytes(data, raf);
//写入MAGIC字节数
writeShort(data.length, raf);
//写入MAGIC
writeBytes(MAGIC, raf);
raf.close();
private static void writeBytes(byte[] data, DataOutput out) throws IOException {
out.write(data);
private static void writeShort(int i, DataOutput out) throws IOException {
ByteBuffer bb = ByteBuffer.allocate(SHORT_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
bb.putShort((short) i);
out.write(bb.array());
在安装包Comment字段写入渠道号的方式,经过测试,并没有修改安装包的内容,用户能成功安装并且使用。
(5)读渠道号关键代码:
//读取源apk的路径
public static String getSourceApkPath(Context context, String packageName) {
if (TextUtils.isEmpty(packageName))
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
return appInfo.sourceD
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
//读取渠道号
public static String readQUA(File file) throws IOException {
RandomAccessFile raf =
raf = new RandomAccessFile(file, &r&);
long index = raf.length();
byte[] buffer = new byte[MAGIC.length];
index -= MAGIC.
//定位到MAGIC处
raf.seek(index);
//读取MAGIC
raf.readFully(buffer);
//判断文件末尾是否存在MAGIC字符
if (isMagicMatched(buffer)) {
index -= SHORT_LENGTH;
raf.seek(index);
//读取渠道号长度
int length = readShort(raf);
if (length & 0) {
raf.seek(index);
//读取渠道号
byte[] bytesComment = new byte[length];
raf.readFully(bytesComment);
return new String(bytesComment, UTF_8);
} finally {
if (raf != null) {
raf.close();
//判断是否存在渠道号
private static boolean isMagicMatched(byte[] buffer) {
if (buffer.length != MAGIC.length) {
for (int i = 0; i & MAGIC. ++i) {
if (buffer[i] != MAGIC[i]) {
读取渠道号有两个步骤:
1、获取安装包的绝对路径。Android系统在用户安装app时,会把用户安装的apk拷贝一份到/data/apk/路径下,通过getSourceApkPath 可以获取该apk的绝对路径。
2、读取渠道号。先定位到文件末尾,判断该文件是否存在写入的MAGIC字符,如果存在再读取渠道号。
这时,我们多渠道的问题也解决了。我们把代码渠道号写入apk的comment字段,也通过代码成功读取到了渠道号。
3、合成新安装包
(1)删除原APK的渠道号
由于我们在生成差异包的时候,两个新旧版本的安装包都是没有渠道号的,而用户在应用市场下载的安装包是我们写入渠道号的安装包,所以我们要把用户正在使用的版本删除渠道号。由于/data/apk/路径,我们只有读取的权限,所以需要把删除渠道号的安装包临时保存起来。
删除渠道号的关键代码:
//删除渠道号
public static int deleteQua(File src, File dest) throws IOException{
if(!src.exists()){
return DELETE_QUA_FAILE_SOURCE_FILE_NOT_EXIST;
long contenLength = getContentLength(src);
if(contenLength & 0){
return DELETE_QUA_FAILE_QUA_NOT_EXIST;
FileInputStream in = new FileInputStream(src.getAbsolutePath());
File file =
if(!file.exists())
file.createNewFile();
FileOutputStream out = new FileOutputStream(file);
long copyed = contenL
byte buffer[] = new byte[1024];
while ((c = in.read(buffer)) != -1) {
if(copyed != c && c == buffer.length){
copyed = copyed -
out.write(buffer, 0, c);
//还原源文件,需要把最后两个字节置为0
表示apk没有注释
buffer[(int) (copyed - 1)] = 0;
buffer[(int) (copyed - 2)] = 0;
out.write(buffer, 0, (int)copyed);
close(in);
close(out);
return SUCCESS;
(2)合成新APK
通过上面步骤,我们可以得到没有渠道号的临时本地安装包,并且和服务器的原始包一致,我们可以使用这个没有渠道号的安装包和已下载的差异包合成新版安装包。由于用户使用的版本可能是破解版,或者下载差异包下载不完整,所以在合成的前需要做文件一致性检验。可以比较文件的md5值,如果MD5值一致,才能进行合成,否则合成失败,直接下载完整的安装包升级。流程如下图:
我们需要把bsdiff中的bspatch.c整合到我们C代码中,并将其编译生so供Android手机使用,其中bspatch依赖bzip2,需要自己下载依赖的c文件。
C关键代码:
#include &stdlib.h&
#include &stdio.h&
#include &string.h&
#include &err.h&
#include &unistd.h&
#include &fcntl.h&
#include &android/log.h&
#include &jni.h&
#include &bzip2/bzlib.c&
#include &bzip2/crctable.c&
#include &bzip2/compress.c&
#include &bzip2/decompress.c&
#include &bzip2/randtable.c&
#include &bzip2/blocksort.c&
#include &bzip2/huffman.c&
#include &com_tencent_smartpatch_utils_PatchUtils.h&
static off_t offtin(u_char *buf) {
y = buf[7] & 0x7F;
y = y * 256;
y += buf[6];
y = y * 256;
y += buf[5];
y = y * 256;
y += buf[4];
y = y * 256;
y += buf[3];
y = y * 256;
y += buf[2];
y = y * 256;
y += buf[1];
y = y * 256;
y += buf[0];
if (buf[7] & 0x80)
int applypatch(int argc, char * argv[]) {
FILE * f, *cpf, *dpf, *
BZFILE * cpfbz2, *dpfbz2, *epfbz2;
int cbz2err, dbz2err, ebz2
ssize_t oldsize,
ssize_t bzctrllen,
u_char header[32], buf[8];
u_char *old, *
off_t oldpos,
off_t ctrl[3];
if (argc != 4)
errx(1, &usage: %s oldfile newfile patchfile\n&, argv[0]);
/* Open patch file */
if ((f = fopen(argv[3], &r&)) == NULL)
err(1, &fopen(%s)&, argv[3]);
File format:
&BSDIFF40&
sizeof(newfile)
bzip2(control block)
bzip2(diff block)
bzip2(extra block)
with control block a set of triples (x,y,z) meaning &add x bytes
from oldfile to x bytes copy y bytes from the
seek forwards in oldfile by z bytes&.
/* Read header */
if (fread(header, 1, 32, f) & 32) {
if (feof(f))
errx(1, &Corrupt patch\n&);
err(1, &fread(%s)&, argv[3]);
/* Check for appropriate magic */
if (memcmp(header, &BSDIFF40&, 8) != 0)
errx(1, &Corrupt patch\n&);
/* Read lengths from header */
bzctrllen = offtin(header + 8);
bzdatalen = offtin(header + 16);
newsize = offtin(header + 24);
if ((bzctrllen & 0) || (bzdatalen & 0) || (newsize & 0))
errx(1, &Corrupt patch\n&);
/* Close patch file and re-open it via libbzip2 at the right places */
if (fclose(f))
err(1, &fclose(%s)&, argv[3]);
if ((cpf = fopen(argv[3], &r&)) == NULL)
err(1, &fopen(%s)&, argv[3]);
if (fseeko(cpf, 32, SEEK_SET))
err(1, &fseeko(%s, %lld)&, argv[3], (long long) 32);
if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
errx(1, &BZ2_bzReadOpen, bz2err = %d&, cbz2err);
if ((dpf = fopen(argv[3], &r&)) == NULL)
err(1, &fopen(%s)&, argv[3]);
if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
err(1, &fseeko(%s, %lld)&, argv[3], (long long) (32 + bzctrllen));
if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
errx(1, &BZ2_bzReadOpen, bz2err = %d&, dbz2err);
if ((epf = fopen(argv[3], &r&)) == NULL)
err(1, &fopen(%s)&, argv[3]);
if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
err(1, &fseeko(%s, %lld)&, argv[3],
(long long) (32 + bzctrllen + bzdatalen));
if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
errx(1, &BZ2_bzReadOpen, bz2err = %d&, ebz2err);
if (((fd = open(argv[1], O_RDONLY, 0)) & 0)
|| ((oldsize = lseek(fd, 0, SEEK_END)) == -1)
|| ((old = malloc(oldsize + 1)) == NULL)
|| (lseek(fd, 0, SEEK_SET) != 0)
|| (read(fd, old, oldsize) != oldsize) || (close(fd) == -1))
err(1, &%s&, argv[1]);
if ((new = malloc(newsize + 1)) == NULL)
err(1, NULL);
oldpos = 0;
newpos = 0;
while (newpos & newsize) {
/* Read control data */
for (i = 0; i &= 2; i++) {
lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
if ((lenread & 8)
|| ((cbz2err != BZ_OK) && (cbz2err != BZ_STREAM_END)))
errx(1, &Corrupt patch\n&);
ctrl[i] = offtin(buf);
/* Sanity-check */
if (newpos + ctrl[0] & newsize)
errx(1, &Corrupt patch\n&);
/* Read diff string */
lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
if ((lenread & ctrl[0])
|| ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
errx(1, &Corrupt patch\n&);
/* Add old data to diff string */
for (i = 0; i & ctrl[0]; i++)
if ((oldpos + i &= 0) && (oldpos + i & oldsize))
new[newpos + i] += old[oldpos + i];
/* Adjust pointers */
newpos += ctrl[0];
oldpos += ctrl[0];
/* Sanity-check */
if (newpos + ctrl[1] & newsize)
errx(1, &Corrupt patch\n&);
/* Read extra string */
lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);
if ((lenread & ctrl[1])
|| ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
errx(1, &Corrupt patch\n&);
/* Adjust pointers */
newpos += ctrl[1];
oldpos += ctrl[2];
/* Clean up the bzip2 reads */
BZ2_bzReadClose(&cbz2err, cpfbz2);
BZ2_bzReadClose(&dbz2err, dpfbz2);
BZ2_bzReadClose(&ebz2err, epfbz2);
if (fclose(cpf) || fclose(dpf) || fclose(epf))
err(1, &fclose(%s)&, argv[3]);
/* Write the new file */
if (((fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0666)) & 0)
|| (write(fd, new, newsize) != newsize) || (close(fd) == -1))
err(1, &%s&, argv[2]);
free(new);
free(old);
JNIEXPORT jint Java_com_tencent_smartpatch_utils_PatchUtils_patch(JNIEnv *env,
jclass obj, jstring old_apk, jstring new_apk, jstring patch) {
char * ch[4];
ch[0] = &bspatch&;
ch[1] = (char*) ((*env)-&GetStringUTFChars(env, old_apk, 0));
ch[2] = (char*) ((*env)-&GetStringUTFChars(env, new_apk, 0));
ch[3] = (char*) ((*env)-&GetStringUTFChars(env, patch, 0));
int ret = applypatch(4, ch);
(*env)-&ReleaseStringUTFChars(env, old_apk, ch[1]);
(*env)-&ReleaseStringUTFChars(env, new_apk, ch[2]);
(*env)-&ReleaseStringUTFChars(env, patch, ch[3]);
java关键代码:
* apk 合成类
public class PatchUtils {
public static final String TAG = &PatchUtils&;
System.loadLibrary(&apksmartpatchlibrary&);
* native方法 使用路径为oldApkPath的apk与路径为patchPath的补丁包,合成新的apk,并存储于newApkPath
* 返回:0,说明操作成功
* @param oldApkPath 示例:/sdcard/old.apk
* @param newApkPath 示例:/sdcard/new.apk
* @param patchPath
示例:/sdcard/xx.patch
public static native int patch(String oldApkPath, String newApkPath, String patchPath);
至此,我们调用 PatchUtile.patch方法即可生成最新的安装包。
再重复一下完整过程:
1、编译打包APK(未写入渠道号)
2、服务器用新旧APK(未写入渠道号)生成差异包
3、APK写入渠道号,供用户下载使用
4、用户本地APK删除渠道号
5、根据用户使用版本下载差异包
6、用本地删除渠道号的APK+下载的差异包生成最新版本APK
四、参考资料
1、 http://www.daemonology.net/bsdiff
2、 https://en.wikipedia.org/wiki/Zip_(file_format )
3、 /cundong/SmartAppUpdates
/mcxiaoke/packer-ng-plugin
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 lol十周年礼物没收到 的文章

 

随机推荐