直播应用送礼大动画完成葡京娱乐总站平台

  • ### 背景

    scrum的飞速开发当中有为数不少有助于项目推进的方法和方案,
    可以最大限度的施用开发人士有限的日子,可是只逗留在管理
    艺术、沟通联络情势等****集体进行****地点。一方面要迅猛迭代、火速容错,
    一边又要因为不断须要有成品营造,开发人士不得不每一天
    很多次重复的创设代码、测试代码、安排代码。

    这一派大家借鉴XP(什么是XP)中
    编程实践手段,利用连发集成技术什么样是无休止集成),测试驱动开发(TDD),结对编程
    来支撑敏捷开发的档次拉动。

送礼物作为观众打赏帮助主播的一种方法, 也是直播应用的一大收益来自,
每个直播平台都包罗送礼这一成效, 并且都把红包动画效果做的尤其炫酷.
如此的动画片效果再搭配美丽的女生或帅哥主播的一句”谢谢某某某送的大飞机~”,
是或不是思考都有点小震动, 感觉弹指间改为了全场的枢纽?

正文主要描述的就是大红包动效的兑现. 全文共3000字左右,
大概阅读时间为5~12分钟.

  • ### 索引

先放上按种类帧播放方案完毕的卡通引擎FXAnimationEngine,
Demo中落实了直播间礼物队列、礼物配置、礼物列表,
别的还分别用动画引擎与原生Core Animation去播放体系帧动画以做相比.

接下来国际惯例, 上两张图

梦幻城堡

天使

  • ### 选用打造工具

自己简单总计了瞬间多少个开源持续集成工具(详细的可比可以活动点我):

一、直播应用礼物动画的大面积方案

仅个人精晓, 落成iOS侧动画配置化常见方案有如下三种:

iOS方案 优点 缺点
Core Animation(此处不计CAKeyFrameAnimation) 效果流畅逼真 安卓需重新实现; 配置化成本高, 需自定义模型、协议、转换方法等(iOS侧已有现成工具, 某几家直播公司想必也有自己的动画配置化工具); 不解决动态配置问题, 则只能随包更新.
序列帧播放(CAKeyframeAnimation、CADisplaylink、ImageView等) 设计哥工具可直接导出动画序列帧图片, 简单易用; 多平台兼容 效果略差; 图片帧数多易导致资源大
Cocos2d-x 效果好; 多平台兼容 学习成本; 相应动画制作工具; 必须引入Cocos2d库;
Lottie 横跨三端, iOS, Android, React Native. 设计师可以完全按照自己的想法设计. 无需考虑实现这一块. 内存占用? 作者本人尚未使用过, 不敢妄自评论

可以看出, 连串帧播放方案是其中最简易易行的一个. 在我看来,
花椒直播用的即是那套方案, 他们每一个动画片,
都会相应一个配备文件config.ini及对应当动画的装有种类帧图片.

感兴趣的仇敌可以移至最终一局地礼物资源的下载策略、资源目录结构等连锁内容,
更提议尝试去研讨一下花椒、映客等主流直播应用的bundle目录以及document中的资源.

  • Jenkins 使用java语言编写 出色的插件环境,协助增添
  • Buildbot python语言开发的档次
    已经为Mozilla、Webkit、Chromium所援助
  • Travis 适合新手 提供Saas 接入github账户
  • Strider 由node.js+javascript编写 需求安装mongodb和node.js
    须要编制脚本 上手困难
  • Drone 开源的,帮助各个语言的CI工具 不过你的档次必须是开源的
    https://drone.io

二、种类帧播放方案执行

综上,集团项目中关系到ios、android、java三种环境,并且代码并不开
源,所以在时时刻刻创设工具中运用Jenkins再合适不过。别的Jenkins
有很好地增添能力,有很完善的插件接济种种条件的代码打造。
Jenkins本身是java达成,在tomcat中就能很好地运行,
这点相比较适合java出身的开发同仁。

2.1 达成格局

队列帧播放动画一方案的具体贯彻必须能够满足以下必要:

  1. 图片突显: CALayer、UIImageView
  2. 按时间距离逐帧播放:
    CAKeyframeAnimation、UIImageView、定时器类(CADisplayLink、NS提姆er、dispatch_source_t)+切换关键帧逻辑
  3. 提供具有体系帧播放完的轩然大波: CAAnimationDelegate、CATransaction
    CompletionBlock、定时器类+回调触发逻辑

结缘形式很多, 比如: CALayer+CAKeyframeAnimation+delegate,
UIImageView+定时器, CALayer+定时器类等等.

大家先选定这一套组合展开实践: CALayer+CAKeyframeAnimation+delegate

// 伪代码
- (void)startAnimation {
    UIImage *frame = [UIImage imageWithContentsOfFile:...];
    NSArray<UIImage *> *frames = @[(id)frame.CGImage, ...];
    CAKeyframeAnimation *keyframeAnim = ...;
    keyframeAnim.contents = frames;
    ...
    keyframeAnim.delegate = self;
    [xxx.layer addAnimation:keyframeAnim forKey:@"xxx"];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    // 触发动画播放结束(全部播放完、中途结束)回调
    ...
}

若果这里你早就下载了Demo, 可以打开Debug
Navigator(cmd+6)不难翻看内存增加或者留意Xcode
Instrument-Allocations中VM:ImageIO_PNG_Data一项,
就会看到有内存增进波峰. 而且体系帧图片更多, 波峰越显然.

那么其余方案是或不是出现了同等的标题呢? 是的, 其他方案一样会如此,
换成UIImageView自带的animationImages来做连串帧播放或是其余组成措施,
也应运而生内存激增的情形.

  • ### <span id=”java”>java项目的自动化创设</span>

2.2 驾驭图片加载

在大家搞了然是怎么导致内存激增前, 大家先精通一下图纸从磁盘加载,
到写入内存, 最终显示到显示器上独家都爆发了怎么. 大概分成如下步骤:

  1. 为磁盘中的图片创制映射
  2. IO操作读取图片数据流
  3. 图片解码位图拷贝, 写入内存
  4. 硬件绘制渲染到屏幕

在linux环境下安装Jenkins有三种情势:

2.2.1 映射文件

当大家透过[UIImage imageWithContentsOfFile:]从磁盘加载图片数据流,
实际上只是为此图片创造了一个文书映射数据,
图片文件既没有真的被加载到内存,
更没有被解码成位图的款式可供Core
Animation传递给底层硬件实行渲染, 故此时内存并不会强烈伸张,
也不会面世因为解码操作导致CPU使用增多的意况.
但从互连网下载图片数据不分包在内.

简言之提及一下炫耀文件:

A mapped file uses virtual memory techniques to avoid copying
pages of the file into memory until they are actually needed.

直译就是一个映射文件借助虚拟内存技术来防止当她们还未曾真的使用到时就被拷贝到内存中.

上面来一组比较表达一下:

对照组一

- (void)test1 {
    UIImage *frame = [UIImage imageWithContentsOfFile:filePath];
    // 确保超出局部作用域后, 依旧保持对这个Image对象的强引用
    self.frame = frame;
}
// 待上方函数执行完后, 再查看内存使用情况

对待组二

- (void)test2 {
    UIImage *frame = [UIImage imageWithContentsOfFile:filePath];
    self.imageview.image = frame;
}

大家可以发现相比较组二的内存占用分明比对照组一要多.
即因而imageWithContentsOfFile:创立的UIImage对象后, 内存并没有确定性增高,
等大家将该UIImage对象赋值给UIImageView的image属性后的某部时刻,
内存才出现显著增加.

此地再留多少个问题:

  1. 俺们都晓得imageWithName:办法加载的图样, 会被系统缓存,
    那么首先次经过该格局开展如上八个对照组的试验, 结果什么呢?
  2. 通过imageWithName:办法第2、3..n次加载同名图片时,
    加载的图形数据流会不会重复被解码? 时期CPU占用有没有增加?
  3. 品尝把创设的UIImage对象桥接赋值给CALayer的contents属性, 结果什么?

1.sudo java -jar jenkins.war –httpPort=18080 –ajp13Port=18009

2.2.2 浅谈CALayer的隐式动画及作业

从上一节中,
大家发现当给UIImageView的image属性或CALayer的contents属性赋值Image对象后的某说话,
内存和CPU占用才会并发显著变化. 那是因为每四回Runloop循环, Core
Animation都会在其开始创立一个卡通事务,
在本次Runloop甘休时才去实施所有添加到该事务里的具有动画操作.
此刻图片才被解码加载入内存,
图片数据会被解码为渲染可用的bitmap数据.
一些相关细节可看我另一篇分享.

浅谈CALayer隐式动画及作业

2.yum install jenkins

2.3 解决内存激增难题

现阶段我们面临的题材是无论采纳何种完结方案, 在实施体系帧动画时,
所有图片都会被解码成为位图并载入内存中.

首先种方法下,即使你是SSH连接到linux主机,当您关闭连接的时候,这一个命令也会被搁浅;

2.3.1 解压后的图形所占内存大小

图表解码后的格式为位图方式.
位图是由一组像素(pixel)组成的, 每一个像素就代表图片中的一个点.
比如大规模的JPEG, 以及PNG格式的图纸文件都是位图图片.

咱俩还亟需了解, JPEG和PNG图片实际上都是一种编码/压缩后的位图格式,
它们是不可能一直用来图片渲染的, 所以得先对其缩减的数目开展解码/解压缩操作.

那就是说一张解压后的位图其所占内存大小怎么统计呢?

那边若是大家有一张32位的PNG格式图片, 其像素格式为RGBA四有的组成,
每部分占8位, 该图片尺寸为160px * 320px.

32位的图片意味着其每个像素占32位, 即4个字节.
又根据图片尺寸计算出总像素数量为 160*320 个像素.
所以该图片解码后所占内存大小就为 像素总数 * 单位像素的字节数
即 (160*320) * 4 / 1024 = 200 KB.

由此不问可知, 假诺一个行列帧动画有80张图片, 200 * 80 / 1024 = 15.625
mb, 就会占据15mb的内存. 系列帧图片越来越多, 占用内存越大!

其次种方式,是在CentOS系统中使用yum命令安装(熟练CentOS系统的人应该不陌生),安装到位之后,
Jenkins会成为系统中的一个service,只要在命令行执行service jenkins start|stop|restart
就足以形成劳动的启动为止和重启。

2.3.2 解决方案

那么有如何艺术可以幸免吗? 可以如故不可以老是播放到哪一帧时就去加载那一帧的图纸,
即每便仅加载一张图片到内存中. 这样当播放到下一张图纸时,
上一张图纸已无其余引用, 系统本来会对其展开释放.

那就是最简单易行可行的一套方案.
不过大家不能靠CAAnimation及其派生类CAKeyframeAnimation来完成这一方案,
因为具有的图片都会解码导致占用大量的内存.

但大家得以经过CADisplayLink来落到实处该方案,
选CADisplayLink的原因是它比NS提姆er精度要高很多,
正常状态下CADisplayLink的回调会在屏幕每一遍刷新时触发,
即一般1/60秒触发三次, 适合用来做UI的重绘,
因而得以透过它来周期性的交替关键帧图片, 从而达到播放动画的功用.
那么具体如何是好吗?

在CADisplayLink的回调中获取四次显示器刷新的间隔时间,
通过持续的丰硕间隔时间来判定总的时间是不是已经知足下一帧的广播时刻,
假如大于下一帧的播音时刻就足以轮换为下一帧图片了,
直至最终一张关键帧也播放落成.

举个例子, 大家要在1秒内播放完一个包蕴5张关键帧图片的动画,
每张图片的停留时间、切换时间如下图2.3.2.a所示.
所以第0秒的时候就从头显示第一张关键帧, 直到1.0秒这一阵鼠时, 动画播放截至.

图 2.3.2.a

此外, 假如还索要更为优化,
大家得以插手图片异步解码、图片预加载逻辑等方案.

  • 异步图片解码, 图片解码是一项比较耗时、比较占CPU的操作,
    对于未解码的图形, 系统一般会在主线程对其举行解码,
    所以可以经过在异步线程举行图纸强制解压缩, 从而不占用UI线程.
    关于图片解码的详情, 强烈推荐座谈 iOS
    中图纸的解压缩
    .

  • 图片预加载, 那么些就是为了进一步节约上下文切换时间,
    即前后两张图片切换的时间. 就是要完结当上一帧图片播放完时,
    大家毫不等下一张图片解码已毕后再拓展图纸的切换,
    而是可以一向从已解码图片的缓存队列中取出直接举行切换.
    预加载我个人觉得实在根本就是阈值的最优拔取,
    可参看预加载与智能预加载一文.

  • 字节对齐(byte alignment)对Core
    Animation品质的震慑

安插文件路径为:/etc/sysconfig/jenkins,可能须要root权限。配置文件中一言九鼎要求修改的是开行
端口JENKINS_PORT
(默认是8080),使用jenkins的用户JENKINS_USER(默许生成一个jenkins)。
我这边的用户是cms,端口是8818,

三、种类帧动画引擎源代码及Demo

FXAnimationEngine –
Github跳转

针对该Demo近年来会另起一文越发介绍, 此处占坑, 等待跳转链接

JENKINS_USER=”cms”
JENKINS_AJP_PORT=”8819″

四、礼物资源下载策略及资源目录结构

修改jenkins涉及到的目录和文书的权能所属:

4.1 礼物资源下载策略

sudo chown -R cms /usr/lib/jenkins
sudo chgrp -R cms /usr/lib/jenkins
sudo chown -R cms /var/log/jenkins
sudo chgrp -R cms /var/log/jenkins
sudo chown -R cms /var/lib/jenkins
sudo chgrp -R cms /var/lib/jenkins
sudo chown -R cms /var/cache/jenkins
sudo chgrp -R cms /var/cache/jenkins

4.1.1 二种格局比较

方式 基本思路 优点 缺点
整包更新 所有的动画资源按目录结构进行压缩, 客户端通过比较资源包版本号发现有更新后, 仅需下载一个资源包压缩文件, 并进行解压替换即可 简单易实现, 客户端每次仅需下载一个资源包 随着资源包逐渐增大, 下载及解压时间也会延长, 从而直接影响用户体验; 即使是仅是资源中的某个图片发生改变, 客户端都要重新下载整个资源包, 容错率低且浪费流量
增量更新 每个动画资源单独压缩并上传CDN, 若客户端发现资源版本号有变化, 再对服务器下发的资源列表跟本地资源列表求差集运算从而得出增量, 单个动画资源的下载地址或者md5可作为唯一标识进行比较. 得出增量后, 客户端再对每个增量资源包进行下载, 每下载完一个即可"投入使用" 不怕资源变更频繁; 仅需下载有新增或有变更的资源包, 更节省时间以及流量; 逻辑略复杂于整包更新, 比如下载中途用户把应杀掉, 下次需要找出未更新完的增量资源并继续下载

之后就足以启动Jenkins了,执行命令sudo service jenkins start

4.1.2 资源创新流程

因对上家集团的代码保密, 此处不上实际代码

大家在上一小节中提及的二种更新格局,
它们首要的差距的就在于”资源创新”这一手续

图 4.1.2.a 整包更新的流程图

整包更新流程图.png

图 4.1.2.b 增量更新的流程图

增量更新流程图.png

不亮堂诸位发现八个流程共同之处没? 它们都急需检测资源版本号大小,
包罗游戏补丁、热更补丁这一步骤都必不可少. 相比较于补丁类的,
资源立异不用太考虑灰度发表、回滚机制等题材, 但如故照样须要小心资源核查,
内部测试, 以及日志监控等维持,
我记得在前人公司就碰见了一部分地点下载下来的资源包有难点,
所以不管是CDN的标题或资源本身有标题, 前端都亟待为最坏的场合做好打算,
那才是万全之计.

引用我上家商店, 我老大兼mentor, 达文哥, 告诫的一句箴言

无须相信后台下发的多少都是科学的

大体意思那样, 原句没背下来, 那句话绝非不是指后台同学好生,
或者甩锅给后台
, 而是要prepare for the worst.

左右端测试都是一家人, 蒙受标题我们先看看是否团结难题,
不要相互甩锅..本是同根生相煎何太急, 如若有难点就一块搓一顿,
一顿不行就再来一顿

show

4.2 资源目录结构设计

任凭哪个直播平台, 每个礼物都会相应一个逻辑id,
我们得以经过礼物的id作为该赠品的资源目录名,
然后在该目录内在去划分不相同档次的图片子目录, 如下所示

- 10000             // 一级目录, 礼物id
    - - gift        // 二级目录, 小礼物序列帧图片
    - - giftlist    // 二级目录, 礼物列表序列帧图片 
    - - giftanim    // 二级目录, 大动画序列帧图片

这只是里面的一种设计, 也有的平台会利用如下格局, 所以主要仍旧看须要而定

- gift
    - - 10000
- giftlist
    - - 10000
- giftanim
    - - 10000   

除此以外, 有的阳台还会选择id_version, 即礼物id+礼物版本的款式来命名,
那样可以便宜配置使后台可以灵活下发给前端具体要去播放哪个动画的某个版本了

- 10000_11  // id为10000, 版本为11的礼物资源目录
- 10000_12

jenkins安装好之后,首先须要肯定你本地是还是不是有:

Maven 负责编译java代码
Git 负责从代码管理服务器中拉取最新提交的代码
JDK 那些就不用说了,你没有jenkins你也设置不了

好了,那里就不赘述以上工具的环境变量的配备了,一定要有。

开辟Jenkins主界面,首先下载打造所需的插件,依次进入系统管理管理插件,下载:

GIT plugin
Maven Integration plugin
Email Extension Plugin
(对jenkins自带邮件文告的增添,能够自定义邮件模板)

配置Jenkins 系统管理系统设置

此间最重假设对maven、Git、JDK的门路做一些布署

system-config

只要你下载了Email Extension
Plugin
插件,在系统安插中可以安装你想要的邮件通告属性

email-config

系统陈设之后,回到主界面,接纳新建,填写Item名称,选拔打造一个maven项目

create-job

下一步,源码管理中填入你拉取代码的git地址,可以是HTTP协议,也得以是SSH。当然,假若是HTTP,要有
相应的用户名和密码;即使是SSH,用户名和密码是git版本管理所在的服务器主机的用户名和密码,
同时需求在git版本管理器所在服务器上添加ssh登录的auto文件中添加公钥
private key是jenkins所在主机的用户私钥。

config-git

创设触发器中勾选Build whenever a SNAPSHOT dependency is builtPoll SCM
这么打造的触发器,会每三分钟(H/3 * * *
*)轮询四遍你的代码库,只要你往git的develop
支行中commit代码,Jenkins就会打造三遍

config-trigger

编译使用的是maven,所以要确定到maven的pom文件和执行命令,如图

config-build

添加创设后的动作,比如你期望执行什么样shell、邮件文告到developer
要么管理人等

config-email

此间打包好的文书在您的Jenkins主目录/var/lib/jenkins下地workspace里面,并且会保留
您每趟的营造代码包,有关打造为止的配备工作,你可以自己写shell剧本执行,也得以在pom文件中
写关于tomcat的插件属性,利用maven直白将代码布署到tomcat的安插目录下(其中也事关到走访权限
的难题,那里就不开展叙述了)。

回来主目录,你的打造job会在job
list中突显,其中S的水彩用来分别你营造战败仍然成功,
紫色是打响,灰色是没戏;W代表您近日一次打造的场馆

show-jobs

除此之外自行触发构建职分,你也得以手动布置一遍打造

build-list

下图为每一趟测试结果的一个总括图:

show-test

在转移记录中,能看出每一趟构建中,提交了怎么着代码,commit的comments,哪个人提交的等等

show-summary

更现实的打造音讯可以查阅Console Output ,如下图:

show-console

让自身很爽快的是,当Jenkins自动营造形成之后,我会收到一个邮件提示

show-email

末尾,别让你的系统什么人都足以访问,用户权限在首页-> 系统管理->
Configure Global Security里配置。

  • ### <span id=”ios”>ios项目的自动化打造</span>

在Mac上安装Jenkins正如便利,只要从官网上下载dmg安装包就能够。

注意:倘若您Mac上得JDK不是1.7+,安装会失利。

卸载Jenkins执行:/Library/Application Support/Jenkins/Uninstall.command

安装之后,Mac上会多出一个用户:Jenkins,若是你想更改成为您的用户来推行Jenkins,先停掉jenkins,
更改配置文件,再重启jenkins服务(launchctl有点像linux的瑟维斯),如下执行:

sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist

sudo vim +1 +/daemon +'s/daemon/staff/' +/daemon +'s/daemon/bixiaopeng' +wq org.jenkins-ci.plist

sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist

别忘了修改日志目录的用户权限和主目录的用户权限。

ios的app打造必要有xcode环境,所以你的布署必将是台mac电脑,但我们做的也是机关创设,所以毫无疑问不能利用
xcode可视化工具举办营造,所以我尝试了xcodebuild,大约步骤是:build->archive->IPA

xcodebuild -alltargets clean

xcodebuild -target HelloJenkins PROVISIONING_PROFILE="00000000-0000-0000-0000-000000000000" CONFIGURATION_BUILD_DIR=JenkinsBuild

xcodebuild -scheme HelloJenkins archive PROVISIONING_PROFILE="00000000-0000-0000-0000-000000000000" CODE_SIGN_IDENTITY="iPhone Developer: Justin Hyland (XXXXXXXXXX)" -archivePath ./JenkinsArchive/HelloJenkins.xcarchive

xcodebuild -exportArchive -exportFormat IPA -exportProvisioningProfile iOS\ Team\ Provisioning\ Profile:\ com.yourAPP.HelloJenkins -archivePath ./JenkinsArchive/HelloJenkins.xcarchive -exportPath ./JenkinsIPAExport/HelloJenkins.ipa

详见:http://www.cnblogs.com/rosepotato/p/3884851.html

不过创设并没有设想当中的风调雨顺,假如你选用了第三方的jar包,总是会报错:

no provisioning profile matches ‘xxx’

由此调研,发现xcodebuild可以通过workspace文件营造,可以避开那一个题材,
前提是您有scheme文件,跟ios的同时联系完将来,他老是提交代码都会share
scheme
文本上来。创设偶尔成功,可是照旧持续报错。

xcodebuild -workspace MyProject.xcworkspace -scheme MyScheme SYMROOT=$(PWD)/build

末了的创设成功是借鉴了刘先宁在InfoQ上的一篇文章(创设iOS持续集成平台(一)——自动化打造和依靠管理

其实是利用到了FaceBook给出的代表xcodebuild的化解方案xctool
当下感到,我前边就恍如一直在用javac编译java代码,而不明了还有maven这些东西。
因此xctool和cocoapod,代码创设成功。

xctool -workspace SDJG.xcworkspace -scheme SDJG clean

xctool -workspace SDJG.xcworkspace -scheme SDJG build SYMROOT=$(PWD)/JenkinsBuild

xcrun -sdk iphoneos PackageApplication -v bbbuild/Debug-iphoneos/SDJG.app -o /Users/fangrichird/git/shangde1216/JenkinsIPAExport/SDJG.ipa

ios项目也就只停留在IPA那里了,因为TestFlight自从被苹果收购之后,
再无法经过jenkins的插件达成上传。解决办法停留在手动将IPA发向各类云
服务平台,或者直接用iTunes安装到测试机当中。

有关jenkins用到的插件和其余条件布署,请参考
java篇

  • ### <span id=”android”>Android项目的自动化营造</span>

    Android的集成布署相对来说比较简单,跟大家的android工程师沟通,他们习惯使用
    Android studio那种购并的ide,假设安顿,有集成在IDE中的Gradle。

    据此想要在linux上创设Android代码,只须要两件事情:

    1.安装Android SDK;
    2.配备Gradle环境;(JDK环境就毫无说了啊)

    other和java篇的布局相同,只是再必要安装一个Gradle插件,倘使
    你要求向分化的应用市场打包,在Gradle的计划文件中安插就好了。