Unity3D手游开发执行

A survey of garbage collection and the changes CLR 4.0 brings in –
series of what is new in CLR 4.0
导言Introduction
  垃圾回收(Garbage Collection)在.net中是一个很重点的机制.
本文将要谈到CLR4.0对废品回收做了咋样改革. 为了更好地明白这个立异,
本文也要介绍垃圾回收的历史.  这样我们对所有垃圾回收有一个大的映像.
那个大映像对于大家领悟.net架构是有帮助的.

《腾讯桌球:客户端总计》

  Garbage Collection is an important component of .net. The post will
talk about what has been improved in CLR 4.0. To understand it, I will
take a survey of the history of garbage collection. This way we can have
a big picture of garbage collection. This will help us master .net
architecture in comprehensive manner.

本次分享总计,起点于腾讯桌球项目,可是不仅仅限于项目自身。即便基于Unity3D,很多事物一样适用于Cocos。本文从以下10大点举办阐释:

至于垃圾回收About Garbage collection
  在C++时代,我们需要协调来保管申请内存和释放内存. 于是有了new,
delete关键字. 还有的有些内存申请和自由函数(malloc/free).
C++程序必须很好地管理自己的内存, 不然就会造成内存泄漏(Memory leak).
在.net时代, 微软为开发人士提供了一个有力的建制–垃圾回收.
垃圾回收机制是CLR的一有些, 我们毫不担心内存啥时候释放,
我们得以花更多精力关注应用程序的作业逻辑.
CLR里面的废品回收机制用自然的算法判断某些内存程序不再行使,回收这一个内存并付出大家的先后再使用.

  1. 架构设计

  2. 原生插件/平台相互

  3. 本子与补丁

  4. 用剧本,仍旧不要?这是一个问题

  5. 资源管理

  6. 特性优化

  7. 异常与Crash

  8. 适配与配合

  9. 调剂及开发工具

  10. 项目运营

  In the times of C++, we need to allocate and release memory by
ourselves carefully,  therefore there are new, delete keywords in C++,
and fuctions(malloc/free) to allocate and release memory. C++ program
has to manage its memory well, otherwise there will be memory leak. In
.net, Microsoft provides a strong machanism to developers—Garbage
collection. The Garbage collection is part of CLR. We do not need to
worry about when to release memory. We can spend more time on buisness
logic of applications. The Garbage colleciton of CLR adopts algorithms
to decide which part of memory the program does not need any more, and
then release these memory for further use.

图片 1图片 2图片 3

污染源回收的功力The functionalities of Garbage collection
  用来管理托管资源和非托管资源所占据的内存分配和假释。In charging of the
releasing and re-allocation of memory of managed and unmanaged
resources.

 

  寻找不再动用的目的,释放其占用的内存, 以及自由非托管资源所占有的内存.
Find the objects no longer needed, release the memory the objects
occupied, and affranchise memory occupied by unmanaged resources.

1.架构设计

  垃圾回收器释放内存之后, 出现了内存碎片, 垃圾回收器移动部分对象,
以得到整块的内存,同时具有的目的引用都将被调动为指向对象新的囤积地点。After
releasing the memory no longer needed, there is memory scrap. Garbage
collector shifts objects to get consecutive memory space, and then the
references of objects will be adjusted according to the shifted address
of objects.

图片 4

下边大家来看望CLR是咋样保管托管资源的. Let’s see how CLR takes care of
managed resources.

好的架构利用常见项目标两个人团体开发和代码管理,也运用查找错误和先前时期维护。

托管堆和托管栈Managed heap and Managed stack:
.net
CLR在运作我们的主次时,在内存中开拓了两块地点作不同的用处–托管栈和托管堆.
托管栈用来存放在局部变量, 跟踪程序调用与再次来到. 托管堆用来存放引用类型.
引用类型总是存放于托管堆. 值类型一般是放在托管栈上边的.
假设一个值类型是一个引用类型的一片段,则此值类型随该引用类型存放于托管堆中.
哪些东西是值类型? 就是概念于System.ValueType之下的这些项目:

  • 框架的采纳:需要遵照公司、项目来举行接纳,没有最好的框架,只有最合适的框架。

  • 框架的行使:统一的框架能正式我们的一言一行,互相之间可以相比较平缓切换,可维护性大大提升。除此之外,还可以代码解耦。例如StrangeIOC是一个超轻量级和惊人可扩充的操纵反转(IoC)框架,专门为C#和Unity编写。已知公司里面使用StrangeIOC框架的游戏有:腾讯桌球、欢乐麻将、植物大战僵尸Online。<https://github.com/strangeioc/strangeioc>

bool byte char decimal double enum float int long sbyte short struct
uint ulong ushort

 

When .net CLR runs our program, CLR declares two ranges of memory for
different purposes. Managed stack is to store local variables, and trace
the call and return of routines. Managed heap is to store reference
types. Usually value types was put on managed stack. If a value type is
a part of a reference type, then the value type will be stored in
managed heap along with the reference type. What are value types? They
are the types defined in System.ValueType:

依傍注入(Dependency Injection,简称DI),是一个首要的面向对象编程的原理来缩短总结机程序的耦合问题。依赖注入还有一个名字叫做控制反转(Inversion of Control,英文缩写为IoC)。依赖注入是这么一个经过:由于某客户类只依靠于服务类的一个接口,而不借助于于现实服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运作上下文环境特意组件顶住实例化服务类,然后将其注入到客户类中,保证客户类的正规运作。即对象在被创立的时候,由一个运行上下文环境或专门组件将其所依靠的服务类对象的引用传递给它。也能够说,看重被注入到目的中。据此,控制反转是,关于一个目的如何收获她所依靠的对象的引用,这多少个责任的反转

bool byte char decimal double enum float int long sbyte short struct
uint ulong ushort

 

哪些是援引类型呢? 只要用class, interface, delegate, object,
string注明的品种, 就是引用类型.  What are reference types? The types
declared with class, interface, delegate, object, stirng, are reference
types.

图片 5

我们定义一个片段变量, 其体系是援引类型. 当大家给它赋一个值, 如下例:We
declare a local variable, which is a reference type, and we assign a
value to the local variable, like the following:

 

private void MyMethod()
{
   MyType  myType = new MyType();
   myType.DoSomeThing();
}
在此例中, myType 是有些变量, new实例化出来的靶子存储于托管堆,
而myType变量存储于托管栈.
在托管栈的myType变量存储了一个针对托管堆上new实例化出来目的的引用.
CLR运行此方法时, 将托管栈指针移动, 为一些变量myType分配空间,
当执行new时, CLR先查看托管堆是否有丰富空间,
充分的话就只是简短地活动下托管堆的指针, 来为MyType对象分配空间,
尽管托管堆没有丰裕空间, 会引起垃圾收集器工作.
CLR在分配空间从前,知道所有项目标元数据,所以能精通各类类其它分寸,
即占用空间的大小.

StrangeIOC选用MVCS(数据模型 Model,体现视图 View,逻辑控制 Controller,服务瑟维斯(Service))结构,通过音讯/信号举行交互和通信。整个MVCS框架跟flash的robotlegs基本一致,(忽略语言不相同)详细的参考<http://www.cnblogs.com/skynet/archive/2012/03/21/2410042.html>。

In this sample, myType is a local variable. the object instantiated by
new operation is stored in managed heap, and the myType local variable
is stored in managed stack. The myType local variable on managed stack
has a pointer pointing to the address of the object instantiated by new
operation. When CLR executes the method, CLR moves the pointer of
managed stack to allocate memory for the local variable myType. When CLR
executes new operation, CLR checks first whether managed heap has enough
space, if enough then do a simple action – move the pointer of managed
heap to allocate space for the object of MyType. If managed heap does
not have space, this triggers garbage collector to function. CLR knows
all the metadata of types, and knows the size of all the types, and then
knows how big space the types need.

  • 数据模型 Model:紧要负责数据的贮存和主导数据处理

  • 来得视图 View:重要承担UI界面显示和动画表现的拍卖

  • 逻辑控制 Controller:首要承担作业逻辑处理,

  • 劳动Service:重要担负独立的网络收发请求等的局部职能。

  • 信息/信号:通过消息/信号去解耦Model、View、Controller、瑟维斯(Service)这四种模块,他们之间通过音信/信号举办相互。

  • 绑定器Binder:负责绑定音信处理、接口与实例对象、View与Mediator的应和关系。

  • MVCS Context:可以精晓为MVC各种模块存在的上下文,负责MVC绑定和实例的制造工作。

当CLR完成MyMethod方法的执行时, 托管栈上的myType局部变量被随即删除,
不过托管堆上的MyType对象却不自然即刻删除.
这有赖于垃圾收集器的触及条件.后边要介绍此触发条件.When CLR finishs
execution of MyMethod method, the local variable myType on managed stack
is deleted immediately, but the object of MyType on managed heap may not
be deleted immediately. This depends on the trigger condition of garbage
collector. I will talk about the trigger condition later.

图片 6

下边我们精通了CLR怎么着管理托管资源.
下边我们来看垃圾收集器怎样寻找不再拔取的托管对象,并释放其占用的内存. In
previous paragraphs, we learn how CLR manages managed resources. In
following paragraphs, we will see how garbage collector find objects no
longer needed, and release the memory.

腾讯桌球客户端项目框架

垃圾收集器怎么样寻找不再接纳的托管对象,并释放其占用的内存How garbage
collector find objects no longer needed and release memory
眼前我们领悟了CLR怎样管理托管栈上的对象.依照先进后出原则即可相比较便于地保管托管栈的内存.
托管堆的治本比托管栈的治本复杂多了.下面所谈都是本着托管堆的管理. In
previous paragraphs, we learn how CLR manages the objects on managed
stack. It is easy to manage managed stack as long as you utilize the
rule “first in last out”. The management of managed heap is much more
complicated than the management of managed stack. The following is all
about the management of managed heap.

 

根The root
垃圾堆收集器寻找不再利用的托管对象时,
其判断遵照是当一个目的不再有引用指向它, 就表明此目的是可以释放了.
一些扑朔迷离的情况下得以现身一个目的指向第二个对象,第二个对象指向第四个目的,…就象一个链表.
那么, 垃圾收集器从哪儿起头查找不再选拔的托管对象啊?
以刚才所说的链表为例, 明显是应该从链表的最先起始查找.
那么,在链表先导的是些什么东东吧? The criteria garbage collector uses to
judge whether an object is no longer needed is that an object can be
released when the object does have any reference. In some complicated
cases, it happends that the first object refers to the second object,
and the second object points to the third object, etc. It is looking
like a chain of single linked nodes. Then the question is : where does
the garbage collector begins to find objects no longer needed? For the
example of the single linked node chain, we can say it is obvious
garbage collector starts from the beginning of the chain. Then the next
question is: what are the stuff at the beginning of the chain.

  • 代码目录的团队:相似客户端用得比较多的MVC框架,怎么划分目录?

    • 先按工作功效划分,再按照 MVC 来划分。”蛋糕心语”就是拔取的那种格局。
    • 先按 MVC 划分,再遵照工作职能区划。”D9″、”婴儿斗场”、”魔法花园”、”腾讯桌球”、”欢乐麻将”使用的这种方法。

是局部变量, 全局变量, 静态变量, 指向托管堆的CPU寄存器.
在CLR中,它们被称之为根. The answer is : local variables, global
variables, static variables, the CPU registers pointing to managed heap.
In CLR, they are called “the roots”.

图片 7

有了启幕点, 垃圾收集器接下来肿么办啊? Got the roots, what will garbage
collector do next?

 

开创一个图, 一个描述对象间引用关系的图. Build a graph, which shows the
reference relationship among objects.
废品收集器首先假定所有在托管堆里面的目的都是不行到达的(或者说没有被引用的,不再需要的),
然后从根上的这一个变量先河, 针对每一个根上的变量,
找出其引述的托管堆上的靶子, 将找到的对象参预这几个图,
然后再顺着那么些目标往下找,看看它有没有引用其它一个对象,
有的话,继续将找到的对象出席图中,要是没有的话,
就表明这条链已经找到尾部了. 垃圾收集器就去从根上的另外一个变量开首找,
直到根上的所有变量都找过了, 然后垃圾收集器才停下查找. 值得一提的是,
在寻觅过程中, 垃圾收集器有些小的优化, 如:
由于目的间的引用关系可能是相比较复杂的, 所以有可能找到一个目的,
而此对象已经进入图了, 那么垃圾收集器就不再在此条链上继续寻找,
转去其他的链上继续找. 这样对垃圾收集器的性能有所改革.

基于使用习惯,可以自动选拔。个人推举”先按工作职能划分,再遵照MVC 来划分”,使得模块更聚焦(高内聚),第二种办法用多了发现随着项目标营业模块增多,没有第一种那么好维护。

First garbage collector supposes all the objects in managed heap are not
reachable( do not have reference, or no longer needed). Then start from
the variables in the roots. For each of the variable in the roots,
search the object the variable refers to, and add the found object into
the graph, and search again after the found object for next refered
object, etc. Check whether the found object has next reference. If has,
continue to add the next found object into the graph. If not, it means
this is the end of the chain, then stop searching on the chain, continue
on next variable in the roots, keep searching on roots, until all the
searching are finished. In the searching process, garbage collector has
some optimization to improve the performance. Like: Because the
reference relationship could be complicated among objects, it is
possible to find an object that has been added into the graph, then
garbage collector stops searching on the chain, continue to search next
chain. This way helps on performance of garbage collection.

  • Unity项目目录的协会:结合Unity规定的一些特殊的用途的文件夹,大家提出Unity项目文件夹协会章程如下。

废品收集器建好这多少个图之后, 剩下那个尚未在这一个图中的对象就是不再需要的.
垃圾收集器就可以回收它们占有的空间.After buidling the reference graph
among objects, the objects not in the graph are no longer needed
objects. Garbage collector could release the memory space occupied by
the no longer needed objects.

图片 8

未完待续To be continued…

个中,Plugins援助Plugins/{Platform}这样的命名规范:

参考文献References
Garbage Collection: Automatic Memory Management in the Microsoft .NET
Framework By Jeffrey Richter 
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

  • Plugins/x86
  • Plugins/x86_64

  • Plugins/Android

  • Plugins/iOS

Garbage Collection Part 2: Automatic Memory Management in the Microsoft
.NET Framework By Jeffrey Richter
http://msdn.microsoft.com/en-us/magazine/bb985011.aspx

假使存在Plugins/{Platform},则加载Plugins/{Platform}目录下的文件,否则加载Plugins目录下的,也就是说,假若存在{Platform}目录,Plugins根目录下的DLL是不会加载的。

Garbage Collector Basics and Performance Hints By Rico Mariani at
Microsoft  http://msdn.microsoft.com/en-us/library/ms973837.aspx

除此以外,资源公司使用分文件夹存储”成品资源”及”原料资源”的办法处理:避免无关资源参预打包,RawResource即原始资源,Resource即成品资源。当然并不限于RawResource这种样式,其他Unity规定的特种文件夹都可以这么,例如Raw
Standard Assets。

http://drowningintechnicaldebt.com/blogs/royashbrook/archive/2007/06/22/top-20-net-garbage-collection-gc-articles.aspx

 

 

  • 集团组件

化妆小游戏
换装小游戏
化妆小游戏
美丽的女人小游戏
古装公主小游戏
化妆仙女小游戏
美容男友小游戏
爱人约会小游戏
婚纱礼服小游戏
阿sue小游戏
做饭小游戏
靓女餐厅小游戏
整容小游戏
美甲小游戏
芭比(Barbie)娃娃小游戏
光洋妹小游戏
布置房间小游戏
照顾婴儿小游戏
祖玛小游戏
一连看小游戏
对对碰小游戏
泡泡堂小游戏
至上玛丽(Mary)小游戏
黄金矿工小游戏
密室逃脱小游戏
魔塔小游戏
找茬小游戏
呈现小游戏
双人小游戏
小家伙小游戏
奥特曼(Ultraman)小游戏
海绵宝宝小游戏
虹猫蓝兔小游戏
哆啦A梦小游戏
喜羊羊与灰太狼小游戏
搞笑小游戏
休闲小游戏
铤而走险小游戏
效仿经营小游戏
棋牌小游戏
测试小游戏
策略小游戏
动作小游戏
体育小游戏
迅猛小游戏
射击小游戏
益智小游戏
综述小游戏

-   msdk(sns、支付midas、推送灯塔、监控Bugly)

-   apollo

-   apollo
    voice 
-   xlua

当下我们的腾讯桌球、四国军棋都衔接了apollo,不过假诺服务器不利用apollo框架,不指出客户端接apollo,而是直接接msdk裁减二次封装音讯的不见和牵动的荒谬,方便将来升迁维护,并且缩小导入无用的代码。

 

  • 其三方插件选型
-   NGUI

-   DoTween

-   GIF

-   GAF

-   VectrosityScripts

-   PoolManager

-   Mad
    Level Manger 

 

2.原生插件/平台相互

图片 9

虽说大多时候利用Unity3D举行娱乐支付时,只需要使用C#拓展逻辑编写。但有时候不可防止的内需接纳和编排原生插件,例如有些第三方插件只提供C/C++原生插件、复用已有些C/C++模块等。有一部分效果是Unity3D实现持续,必须要调用Android/iOS原生接口,比如获取手机的硬件信息(UnityEngine.SystemInfo没有提供的部分)、调用系统的原生弹窗、手机激动等等

 

2.1C/C++插件

图片 10

编制和接纳原生插件的多少个关键点:

  • 始建C/C++原生插件
-   导出接口必须是C ABI-compatible函数
-   函数调用约定
  • 在C#中标识C/C++的函数并调用
-   标识
    DLL 中的函数。至少指定函数的名称和包含该函数的 DLL
    的名称。 
-   创建用于容纳
    DLL 函数的类。可以使用现有类,为每一非托管函数创建单独的类,或者创建包含一组相关的非托管函数的一个类。

-   在托管代码中创建原型。使用 **DllImportAttribute** 标识 DLL
    和函数。 用 **static** 和 **extern** 修饰符标记方法。

-   调用
    DLL 函数。像处理其他任何托管方法一样调用托管类上的方法。
  • 在C#中开创回调函数,C/C++调用C#回调函数
-   创建托管回调函数。

-   创建一个委托,并将其作为参数传递给 C/C++函数。**平台调用会自动将委托转换为常见的回调格式。**

-   确保在回调函数完成其工作之前,垃圾回收器不会回收委托。

 

那么C#与原生插件之间是咋样贯彻互动调用的吗?在弄了然这多少个问题在此以前,我们先看下C#代码(.NET上的程序)的执行的进程:(更详细一点的牵线能够瞻仰我事先写的博客:http://www.cnblogs.com/skynet/archive/2010/05/17/1737028.html

  1. 将源码编译为托管模块;

  2. 将托管模块组成为顺序集;

  3. 加载公共语言运行时CLR;

  4. 施行顺序集代码。

注:CLR(公共语言运行时,Common Language
Runtime)
和Java虚拟机一样也是一个运行时环境,它肩负资源管理(内存分配和污染源收集),并确保应用和底部操作系统之间必要的离别。

为了增进平台的可靠性,以及为了达成面向事务的电子商务应用所要求的安静级别,CLR还要承受其他一些职责,比如监视程序的运作。遵照.NET的传教,在CLR监视之下运行的顺序属于“托管”(managed)代码,而不在CLR之下、直接在裸机上运行的采取或者零部件属于“非托管”(unmanaged)的代码

这么些经过本身总计为下图:

图片 11


.NET上的程序运行

回调函数是托管代码C#中的定义的函数,对回调函数的调用,实现从非托管C/C++代码中调用托管C#代码。那么C/C++是什么调用C#的吧?大致分为2步,可以用下图表示:

图片 12

  • 将回调函数指针注册到非托管C/C++代码中(C#中回调函数指委托delegate)

  • 调用注册过的托管C#函数指针

相比托管调用非托管,回调函数情势有点复杂一些。回调函数相当适合重复执行的职责、异步调用等意况下利用

由地点的牵线可以精晓CLR提供了C#程序运行的环境,与非托管代码的C/C++交互调用也由它来完成。CLR提供二种用于与非托管C/C++代码举办交互的体制:

  • 阳台调用(Platform
    Invoke,简称PInvoke或者P/Invoke),它使托管代码可以调用从非托管DLL中导出的函数。

  • COM
    互操作,它使托管代码可以通过接口与组件对象模型 (COM)
    对象交互。考虑跨平台性,Unity3D不应用这种措施。

 平台调用倚重于元数据在运作时追寻导出的函数并封送(马尔斯hal)其参数。 下图展现了这一历程。

图片 13

在意:1.除涉及回调函数时以外,平台调用方法调用从托管代码流向非托管代码,而绝不会以相反方向流动。 虽然平台调用的调用只可以从托管代码流向非托管代码,不过数量仍是可以够当做输入参数或输出参数在多少个样子流动。2.图中DLL表示动态库,Windows平台指.dll文件、Linux/Android指.so文件、Mac
OS
X指.dylib/framework文件、iOS中只可以使用.a。后文都使用DLL代指,并且DLL使用C/C++编写

当”平台调用”调用非托管函数时,它将次第执行以下操作:

  • 招来包含该函数的DLL。

  • 将该DLL加载到内存中。

  • 找寻函数在内存中的地址并将其参数推到堆栈上,以封送所需的数目(参数)。

注意

只在第一次调用函数时,才会查找和加载 DLL 并查找函数在内存中的地址。iOS中使用的是.a已经静态打包到最终执行文件中。

  • 将控制权转移给非托管函数。

 

 2.2Android插件

图片 14

Java同样提供了这样一个扩充机制JNI(Java
Native Interface),可以与C/C++相互通信。

注:

  • JNI wiki-https://en.wikipedia.org/wiki/Java\_Native\_Interface,这里不长远介绍JNI,有趣味的可以自动去研究。如若你还不了解JNI也不用怕,就像Unity3D使用C/C++库一样,用起来如故相比简单的,只需要知道这一个东西即可。并且Unity3D对C/C++桥接器这块做了包装,提供AndroidJNI/AndroidJNIHelper/AndroidJavaObject/AndroidJavaClass/AndroidJavaProxy方便使用等,具体运用前面在介绍。JNI提供了若干的API实现了Java和任何语言的通信(首倘使C&C++)。从Java1.1起初,JNI标准改成java平台的一有些,它同意Java代码和其它语言写的代码举行交互,保证本地代码能干活在任何Java 虚拟机环境下。”

  • 作为文化扩大,提一下Android
    Java虚拟机。Android的Java虚拟机有2个,最起始是Dalvik,前边Google在Android
    4.4体系新增一种拔取运行情势ART。ART与Dalvik
    之间的紧要区别是其持有超前 (AOT) 编译模式。 按照 AOT
    概念,设备安装使用时,DEX 字节代码转换仅举行三回。 相比较于
    Dalvik,这样可实现真正的优势 ,因为 Dalvik 的即时 (JIT)
    编译方法需要在每趟运行应用时都开展代码转换
    。下文中用Java虚拟机代指Dalvik/ART。

 

C#/Java都得以和C/C++通信,那么通过编制一个C/C++模块作为桥接,就使得C#与Java通信成为了或者,如下图所示:

图片 15

注:C/C++桥接器本身跟Unity3D没有一直关联,不属于Android和Unity3D,图中位居Unity3D中是为着代指libunity.so中实现的桥接器以象征真实的气象。

透过JNI既可以用于Java代码调用C/C++代码,也可用以C/C++代码与Java(Dalvik/ART虚拟机)的互相。JNI定义了2个关键概念/结构:JavaVMJNIENVJavaVM提供虚拟机创制、销毁等操作,Java中一个过程可以创制四个虚拟机,可是Android一个经过只好有一个虚拟机JNIENV是线程相关的,对应的是JavaVM中的当前线程的JNI环境,唯有附加(attach)到JavaVM的线程才有JNIENV指针,通过JNIEVN指针能够赢得JNI效能,否则不可知调用JNI函数。

图片 16

C/C++要拜访的Java代码,必须要能访问到Java虚拟机,获取虚拟机有2中艺术:

  • 在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM*
    jvm, void* reserved)
    ,第一个参数会传播JavaVM指针。
  • 在C/C++中调用JNI_CreateJavaVM(&jvm,
    (void**)&env, &vm_args)创建JavaVM指针

所以,俺们只需要在编制C/C++桥接器so的时候定义**JNI_OnLoad(JavaVM* jvm, void*
reserved)方法即可,然后把JavaVM指针保存起来作为上下文使用**。

收获到JavaVM之后,还不可以直接拿到JNI函数去赢得Java代码,必须经过线程关联的JNIENV指针去获取。所以,作为一个好的付出习惯在历次拿到一个线程的JNI相关功效时,先调用AttachCurrentThread();又或者每一回经过JavaVM指针获取当前的JNIENV:java_vm->GetEnv((void**)&jni_env, version),一定是已经附加到JavaVM的线程。通过JNIENV可以获取到Java的代码,例如你想在地头代码中走访一个目的的字段(field),你可以像下边这样做:

  1. 对于类,使用jni_env->FindClass拿到类对象的引用

  2. 对此字段,使用jni_env->GetFieldId获取字段ID

  3. 动用相应的措施(例如jni_env->GetIntField)获取字段的值

看似地,要调用一个方法,你step1.得拿到一个类对象的引用obj,step2.是艺术methodID。那一个ID平日是指向运行时内部数据结构。查找到它们需要些字符串比较,但假使你实在去执行它们获取字段或者做方法调用是特别快的。step3.调用jni_env->CallVoidMethodV(obj, methodID, args)

从地方的示范代码,我们可以看来使用原有的JNI模式去与Android(Java)插件交互是多的繁琐,要团结做太多的工作,并且为了性能需要团结着想缓存查询到的措施ID,字段ID等等。幸运的是,Unity3D已经为我们封装好了这么些,并且考虑了性能优化。Unity3D重要提供了一下2个级其它卷入来支援高效编写代码:

图片 17

注:Unity3D中对应的C/C++桥接器包含在libunity.so中。

  • Level
    1:AndroidJNI、AndroidJNIHelper,原始的卷入相当于大家地点自己编辑的C#
    Wrapper。AndroidJNIHelper 和AndroidJNI自动完成了许多职责(指找到类定义,构造方法等),并且采取缓存使调用java速度更快。AndroidJavaObject和AndroidJavaClass基于AndroidJNIHelper 和AndroidJNI创立,但在处理自动完成部分也有众多和谐的逻辑,那个类也有静态的本子,用来走访java类的静态成员。更详实接口参考帮衬文档:http://docs.unity3d.com/ScriptReference/AndroidJNI.htmlhttp://docs.unity3d.com/ScriptReference/AndroidJNIHelper.html

  • Level
    2:AndroidJavaObject、AndroidJavaClass、AndroidJavaProxy,这么些3个类是依照Level1的包装提供了更高层级的卷入使用起来更简短,这一个在第三有些详细介绍。

 

2.3iOS插件

图片 18

iOS编写插件比Android要简单很多,因为Objective-C也是
C-compatible的,完全匹配标准C语言。
这一个就足以十分简单的包一层 extern
“c”{},用C语言封装调用iOS功效,表露给Unity3D调用。并且能够跟原生C/C++库一样编成.a插件。C#与iOS(Objective-C)通信的法则跟C/C++完全相同:

图片 19

 

 

除了,Unity
iOS扶助插件自动集成模式。所有位于Asset/Plugings/iOS文件夹中后缀名为.m ,
.mm , .c ,
.cpp的文本都将机关并入到已成形的Xcode项目中。可是,最后编进执行文书中。后缀为.h的文件不可能被含有在Xcode的品种树中,但她们将面世在对象文件系统中,从而使.m/.mm/.c/.cpp文件编译。这样编写iOS插件,除了需要对iOS
Objective-C有一定精通之外,与C/C++插件没有距离,反而更简约。

 

3.本子与补丁

图片 20

任何游戏(端游、手游)都应该提供娱乐内更新的门路。一般娱乐分为全量更新/整包更新、增量更新、资源改进。

  • 全量

android游戏内完全安装包下载(ios跳转到AppStore下载)

 

  • 增量:重要指android省流量更新
-   可以使用bsdiff生成patch包

-   应用宝也提供增量更新sdk可供接入

 

  • 资源

Unity3D通过利用AssetBundle即可兑现动态更新资源的效用。

 

手游在贯彻这块时索要留意的几点:

  1. 玩耍发布出肯定要提供娱乐内更新的门径。尽管是删掉测试,保不准这里面需要展开资源仍然BUG修复更新。很多玩家并不知道如何翻新,而且Android手机应用分发平台多样,分发平台本身也不会跟官方同步革新(特别是小的分发平台)。

  2. 更新效能要提供强制更新、非强制更新配置化选项,并点名哪些版本可以不强更,哪些版本必须强更。

  3. 当娱乐提供非强制更新效用之后,现网一定会存在五个版本。尽管需要针对不同版本做不同的翻新,例如配置文件A针对1.0.0.1修改了一项,针对1.0.0.2改动了另一项,2个本子需要各自更新对应的修改,需要协调实现革新策略IIPS不提供这么些效应。当需要复杂的立异策略,推荐自己编排更新服务器和客户端逻辑,不使用iips组件(其实自己实现也很简短)。

![](https://images2015.cnblogs.com/blog/92071/201604/92071-20160419000347366-1630977637.png)

没有运营经验的人会选择二进制,认为二进制安全、更小,这对端游/手游外网只存在一个版本的游戏适合,对一般不强升版本的手游并不适合,反而会对更新和维护带来很大的麻烦。
  1. 布置使用XML或者JSON等文本格式,更便宜多版本的匹配和改进。最最先腾讯桌球客户端采纳的二进制格式(由excel转换而来),不过随着运营配置格式需要扩大字段,这样老版本程序就解析不了新的二进制数据,给兼容和立异带来了很大的麻烦。那样就要求地点提到的针对不一起做不同更新,又或者安排一从头就留下好充分的增加项,其实不管怎么预留扩大也很难跟上要求的更动,而且一先河会把配置表复杂化不过其实只有一张或者几张才会改变结构。
 
  1. iOS版本的送审版本需要连续一定的包含新内容的服务器,现网服务器还不带有新情节。送审通过之后,上架游戏现网服务器会开展更新,iOS版本需要连续现网服务器而非送审服务器,然而这期间又无法修改客户度,这一个切换需要经过服务器下发开关举行支配。例如通过点名送审的iOS游戏版本号,客户端判断当地版本号是否为送审版本,淌倘使连连送审服务器,否则连接现网服务器。

 

4.用本子,仍然不要?这是一个题目

图片 21

有利于更新,收缩Crash(特别是使用C++的cocos引擎)

透过下边一节【版本与补丁】知道要落实代码更新是非常不方便的,正式这多少个原因客户端支付的压力是相比大的,如果出现了相比较严重的BUG必须发强制更新版本,使用脚本可以解决这些题材。

由于Unity3D手游更新资金相比大,而且近来腾讯桌球要求无法强制更新,这致使新本子的移位覆盖率提高相比较慢、出现问题之后难以修复。针对这一个境况,考虑引入lua举办移动开发,后续宣布活动及修复bug只需要公布lua资源,进行资源立异即可,大大降低了披露和修复问题的成本。

可选方案还有使用Html5进展运动开发,近年来游玩中曾经预埋了Html5平移入口,并且一度用来发过”玩家调查”、”腾讯棋牌宣传”等。不过与lua比较,不可能到位与Unity3D的深浅融合,体验不如使用lua,例如不可能操作游戏中的ui、不能够做到复杂界面的造作、不可能复用已有些效益、玩家付费充值跟已有的也会有出入

 

娱乐脚本之王——Lua

在商家内部魔方相比欣赏用lua,火隐忍者(手游)unity+ulua,全民水浒cocos2d-x+lua等等都有使用lua进行付出。我们得以应用公司里面的xlua组件,也足以利用ulua<http://ulua.org/>、UniLua<https://github.com/xebecnan/UniLua>等等。

 

5.资源管理

图片 22

 

5.1资源管理器

图片 23

 


业务并非一直利用引擎或者系统原生接口,而是包装一个资源管理器负责:资源加载、卸载


兼容Resource.Load与AssetBundle资源互相变更需要,开发期间采纳Resource.Load情势而不要打AB包效用更高


加载资源时,不管是联合加载仍然异步加载,最好是行使异步编码形式(回调函数或者新闻通知机制)。如若哪天资源由本地加载改为从服务器按需加载,而游戏中的逻辑都是联名情势编码的,改起来将这些痛苦。其实异步编码格局很粗略,不比同步形式复杂。

 

5.2资源类型

图片 24

 

  • 图形/纹理(对性能、包体影响最大因素)

  • 音频

-   背景音乐,腾讯桌球使用.ogg/.mp3

-   音效,腾讯桌球使用.wav
  • 数据
-   文本

-   二进制
  • 动画/特效

 

5.3图纸-文件格式与纹理格式

图片 25

常用的图像文件格式有BMP,TGA,JPG,GIF,PNG等;
常用的纹路格式有R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等。

 

文件格式是图像为了存储消息而利用的对音讯的特种编码模式,它存储在磁盘中,或者内存中,可是并不能够被GPU所识别,因为以向量总括见长的GPU对于这些扑朔迷离的揣测无能为力。这些文件格式当被游戏读入后,仍然需要经过CPU解压成R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,
A8R8G8B8等像素格式,再传递到GPU端举行应用。

纹理格式是能被GPU所识此外像素格式,能被飞快寻址并采样。举个例子,DDS文件是娱乐支付中常用的文件格式,它其中可以涵盖A4R4G4B4的纹理格式,也可以蕴涵A8R8G8B8的纹路格式,甚至足以分包DXT1的纹理格式。在此地DDS文件有点容器的象征。OpenGL
ES
2.0支撑上述提到的R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,A8R8G8B8等纹理格式,其中
R5G6B5,A4R4G4B4,A1R5G5B5各种像素占用2个字节(BYTE),R8G8B8每个像素占用3个字节,A8R8G8B8各个像素占用
4个字节。

 

据悉OpenGL
ES的回落纹理有常见的如下两种实现:

1)ETC1(埃里克(Eric)(Eric)sson
texture compression),ETC1格式是OpenGL
ES图形标准的一有些,并且被有着的Android设备所支撑。

2)PVRTC
(PowerVR texture compression),支持的GPU为Imagination
Technologies的PowerVR SGX系列。
3)ATITC (ATI texture compression),支持的GPU为Qualcomm的Adreno系列。
4)S3TC (S3 texture
compression),也被称为DXTC,在PC上普遍被接纳,可是在移动装备上或者属于特殊事物。协理的GPU为NVIDIA
Tegra体系。

 

图片 26

 

5.4资源工具

图片 27

有了规范就可以做工具检查,从源头到打包

  • 资源导入检查

  • 资源打包检查

 

6.性能优化

图片 28

掉帧紧要针对GPU和CPU做分析;内存占用大重要针对美术资源,音效,配置表,缓存等分析;卡顿也需要对GPU和CPU峰值分析,其它IO或者GC也易造成。

图片 29

6.1工欲善其事,必先利其器

图片 30

 

  • Unity
    Profiler
  • XCode instruments

  • Qualcomm Adreno
    Profiler

  • NVIDIA
    PerfHUD ES Tegra

 

6.2CPU:最佳标准缩短统计

图片 31

  • 复用,UIScrollView
    Item复用,制止频繁创建销毁对象
  • 缓存,例如Transform

  • 运算裁剪,例如碰撞检测裁剪

-   粗略碰撞检测(划分空间——二分/四叉树/八叉树/网格等,降低碰撞检测的数量)

-   精确碰撞检测(检查候选碰撞结果,进而确定对象是否真实发生碰撞)

-   休眠机制:避免模拟静止的球
  • 逻辑帧与渲染帧分离

  • 分帧处理

  • 异步/多线程处理

 

6.3GPU:最佳标准裁减渲染

图片 32

  • 纹理压缩

  • 批处理减弱DrawCall(unity-Static
    Batching和Dynamic Batching,cocos Coca ColaBatchNode)

  • 减去无效/不必要绘制:屏幕外的剪裁,Flash脏矩阵算法,

  • LOD/特效分档

  • NGUI动静分离(UIPanel.LateUpdate的耗费)

  • 控制角色骨骼数、模型面数/顶点数

  • 降帧,并非所有场景都亟待60帧(腾讯桌球游戏场景60帧,其他场景30帧;每一日酷跑,在初叶游戏前,FPS被界定为30,游戏开端未来FPS才为60。每日飞车的FPS为30,可是当用户一段时间不点击界面后,FPS自动降)

 

6.4内存:最佳标准收缩内存分配/碎片、及时放出

图片 33

  • 纹理压缩-Android
    ETC1、iOS PVRTC 4bpp、windows DXT5
  • 对象池-PoolManager

  • 集合空闲图集

  • UI九宫格

  • 删除不用的剧本(也会占据内存)

 

6.5IO:最佳标准减弱/异步io

图片 34

 

  • 资源异步/多线程加载

  • 预加载

  • 文件收缩

  • 制造统筹资源统一打包,并非texturepacker打包成大图集一定好,会大增文件io时间

 

6.6网络:其实也是IO的一种

图片 35

选拔单线程——共用UI线程,通过事件/UI循环驱动;如故多线程——单独的网络线程?

  • 单线程:由游戏循环(事件)驱动,单线程形式比采取多线程格局开发、维护简单很多,不过性能比多线程要差一些,所以在网络IO的时候,需要注意别阻塞到游戏循环。表达,如果网络IO不复杂的情事下,推荐应用该格局。
-   在UI线程中,别调用可能阻塞的网络函数,优先考虑非阻塞IO

-   这是网络开发者经常犯的错误之一。比如:做一个简单如
    gethostbyname()
    的调用,这个操作在小范围中不会存在任何问题,但是在有些情况中现实世界的玩家却会因此阻塞数分钟之久!如果你在
    GUI 线程中调用这样一个函数,对于用户来说,在函数阻塞时,GUI
    一直都处于 frozen 或者 hanged
    状态,这从用户体验的角度是绝对不允许的。 
  • 多线程:单独的网络线程,使用独立的网络线程有一个可怜显眼的补益,主线程可以将脏活、累活交给网络线程做使得UI更通畅,例如信息的编解码、加解密工作,这么些都是不行耗时的。不过使用多线程,给支付和掩护带来一定成本,并且只要没有早晚的阅历写出来的网络库不那么平稳,容易失误,甚至招致游戏崩溃。下边是几点注意事项:
-   千万千万别在网络线程中,回调主线程(UI线程)的回调函数。而是网络线程将数据准备好,让主线程主动去取,亦或者说网络线程将网络数据作为一个事件驱动主线程去取。当年我在用Cocos2d-x +
    Lua做魔法花园的手机demo时,就采用的多线程模式,最初在网络线程直接调用主线程回调函数,经常会导致莫名其妙的Crash。因为网络线程中没有渲染所必须的opengl上下文,会导致渲染出问题而Crash。

6.6包大小

图片 36

 

  • 动用压缩格式的纹理/音频

  •  尽量不要采用System.Xml而利用较小的Mono.Xml

  •  启用Stripping来减小库的轻重

  •  Unity
    strip level(strip by byte code)

  •  Unity3D输出APK,取消X86架构

  •  iOS Xcode strip开启

 

6.7耗电

图片 37

下边影响耗电的多少个要素和影响度摘自公司里面的一篇著作。

图片 38

 

 

7.异常与Crash

图片 39

7.1防御式编程

图片 40

 

  • 非法的输入中维护你的主次
-   检查每一输入参数

-   检查来自外部的数据/资源
  • 断言
  • 错误处理

  • 隔栏

 

防不胜防,不管什么防御总有失手的时候,这就需要丰盛捕获和报告。

 

7.2那么些捕获

图片 41

十分捕获已经有好多第三组件可供对接,那里不介绍组件的而接入,而是大概谈一下相当捕获的法则。

图片 42

由于众多谬误并不是发生在支付工作者调试阶段,而是在用户或测试工作者拔取阶段;这就需要有关代码维护工作者对于程序非凡捕获收集现场消息。相当与Crash的督察和上报,这里不介绍Bugly的行使,遵照apollo或者msdk的文档接入即可,没有太多可以说的。那里首要通过Bugly介绍手游的几类分外的抓获和剖析:

  • Unity3D
    C#层非常捕获:比较简单使用Application.RegisterLogCallback/Application.RegisterLogCallbackThreaded(在一个新的线程中调用委托)注册回调函数。特别注意:保险项目中只有一个Application.RegisterLogCallback注册回调,否则前边注册的会覆盖前边注册的回调!回调函数中stackTrace参数包相当调用栈。

public void HandleLog(string logString, string stackTrace, LogType type)

{

    if (logString == null || logString.StartsWith(cLogPrefix))

    {

        return;

    }

   

    ELogLevel level = ELogLevel.Verbose;

    switch (type)

    {

   

        case LogType.Exception:

            level = ELogLevel.Error;

            break;

        default:

            return;

    }

   

    if (stackTrace != null)

    {

        Print(level, ELogTag.UnityLog, logString + "\n" + stackTrace);

    }

    else

    {

        Print(level, ELogTag.UnityLog, logString);

    }

}

 

  • Android
    Java层万分捕获

try…catch显式的捕获非凡一般是不引起游戏Crash的,它又称作编译时这一个,即在编译阶段被处理的分外。编译器会强制程序处理所有的Checked万分,因为Java认为这类异常都是足以被拍卖(修复)的。假设没有try…catch这么些特别,则编译出错,错误指示类似于”Unhandled exception type xxxxx”。
UnChecked非凡又叫做运行时异常,由于没有相应的try…catch处理该特别对象,所以Java运行环境将会停下,程序将退出,也就是我们所说的Crash。这为啥不会加在try…catch呢?

  • 惊慌失措将有着的代码都加上try…catch

  • UnChecked卓殊日常都是较为严重的那一个,或者说已经磨损了运转环境的。比如内存地址,即使大家try…catch住了,也不可能显明明白哪些处理该特别,才能确保程序接下去的周转是无可非议的。

Uncaught非凡会造成应用程序崩溃。那么当崩溃了,我们是不是能够做些什么呢,就像Application.RegisterLogCallback注册回调打印日志、上报服务器、弹窗指示用户?Java提供了一个接口给大家,可以做到这多少个,这就是UncaughtExceptionHandler,该接口含有一个纯虚函数:

public abstract void uncaughtException (Thread thread, Throwableex)

Uncaught非凡暴发时会终止线程,此时,系统便会通告UncaughtExceptionHandler,告诉它被截止的线程以及相应的分外,然后便会调用uncaughtException函数。即使该handler没有被显式设置,则会调用对应线程组的默认handler。假诺大家要捕获该特别,必须贯彻我们自己的handler,并透过以下函数举办设置:

public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler)

特别注意:多次调用setDefaultUncaughtExceptionHandler设置handler,前边注册的会覆盖前边注册的,以最后四回为准。实现自定义的handler,只需要继承UncaughtExceptionHandler该接口,并促成uncaughtException方法即可。

static class MyCrashHandler implements UncaughtExceptionHandler{  

    @Override  

    public void uncaughtException(Thread thread, final Throwable throwable) {  

        // Deal this exception

    }

}

在此外线程中,都得以由此setDefaultUncaughtExceptionHandler来设置handler,但在Android应用程序中,全局的Application和Activity、Service都同属于UI主线程,线程名称默认为”main”。所以,在Application中应当为UI主线程添加UncaughtExceptionHandler,这样全方位程序中的Activity、Service(Service)中冒出的UncaughtException事件都可以被拍卖。

捕获Exception之后,大家还亟需通晓崩溃堆栈的信息,这样有助于咱们分析崩溃的因由,查找代码的Bug。非凡对象的printStackTrace方法用于打印相当的堆栈消息,依据printStackTrace方法的出口结果,我们得以找到非常的源头,并跟踪到充裕联机触及的长河。

public static String getStackTraceInfo(final Throwable throwable) {

    String trace = "";    try {

        Writer writer = new StringWriter();

        PrintWriter pw = new PrintWriter(writer);

        throwable.printStackTrace(pw);

        trace = writer.toString();

        pw.close();

    } catch (Exception e) {        return "";

    }    return trace;

}

  • Android
    Native
    Crash:前面大家领悟可以编制和接纳C/C++原生插件,除非C++使用try…catch捕获十分,否则一般会直接crash,通过捕获信号举办处理。
  • iOS
    分外捕获:

跟Android、Unity类似,iOS也提供NSSetUncaughtExceptionHandler 来做特别处理。

#import "CatchCrash.h"

   

@implementation CatchCrash

   

void uncaughtExceptionHandler(NSException *exception)

{

    // 异常的堆栈信息

    NSArray *stackArray = [exception callStackSymbols];

    // 出现异常的原因

    NSString *reason = [exception reason];

    // 异常名称

    NSString *name = [exception name];

    NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@",name, reason, stackArray];

    NSLog(@"%@", exceptionInfo);

       

    NSMutableArray *tmpArr = [NSMutableArray arrayWithArray:stackArray];

    [tmpArr insertObject:reason atIndex:0];

   

    [exceptionInfo writeToFile:[NSString stringWithFormat:@"%@/Documents/error.log",NSHomeDirectory()]  atomically:YES encoding:NSUTF8StringEncoding error:nil];

}

   

@end

但是内存访问错误、重复释放等不当引起崩溃就不可以了,因为那种似是而非它抛出的是信号,所以还必须要专门做信号处理。

  • windows
    crash:同样windows提供SetUnhandledExceptionFilter函数,设置最高顶级的不行处理函数,当程序出现任何未处理的可怜,都会触发你设置的函数里,然后在相当处理函数中取得程序分外时的调用堆栈、内存音信、线程信息等。

 

 

8.适配与配合

图片 43

 

8.1UI适配

图片 44

 

  • 锚点(UIAnchor、UIWidgetAnchor属性)

  • NGUI UIRoot统一安装缩放比例

  • UIStretch

 

8.2兼容

图片 45

 

  • shader兼容:例如if语句有的机型协理不佳,Googlenexus 6在shader中应用了if就会crash
  • 字体兼容:android复杂的环境,有的手机厂商和rom会对字体举行优化,去掉android默认字体,假诺不打包字体会不现实闽南语字

 

9.调剂及开发工具

图片 46

9.1日记及跟踪

图片 47

事实讲明,打印日志(printf调试法)是至极管用的措施。一个好用的日记调试,必备以下多少个效用:

  • 日记面板/控制台,格式化输出

  • 没完没了级别(verbosity
    level):ERROR、WARN、INFO、DEBUG

  • 频道(channel):按效率等举行模块划分,如网络频道只接到/显示网络模块的音讯,频道指出采取枚举举办命名。

  • 日志同时会输出到日志文件

  • 日记上报

 

9.2调剂用绘图工具

图片 48

调剂绘图用工具指开发及调试期间为了可视化的绘图用工具,如腾讯桌球开发调试时会使用VectrosityScripts可视化球桌的物理模型(实际碰撞线)帮忙调节。这类工具得以省去大量时辰及急速定位问题。平时调试用绘图工具包含:

  • 支撑绘制基本图形,如直线、球体、点、坐标轴、包围盒等

  • 协理自定义配置,如颜色、粒度(线的粗细/球体半径/点的深浅)等

 

9.3游戏内置菜单/作弊工具

图片 49

在开发调试期间提供娱乐展开中的一些配置选项及作弊工具,以便于调试和提升功效。例如腾讯桌球游戏中提供:

  • 游戏内物理引擎参数调整菜系;

  • 修改球杆瞄准线长度/反射线数量、修改签到奖励领取天数等作弊工具

注意游戏内的拥有支出调试用的工具,都亟需经过编译宏开关,保证发布版本不会把工具代码包含进去

 

9.4Unity扩展

图片 50

Untiy引擎提供了老大强大的编辑器扩张效率,基于Unity
Editor可以实现丰富多的机能。公司内部、外部都有相当的开源扩展可用

供销社外部,如GitHub上的:

UnityEditor-MiniExtension

Unity-Resource-Checker

UnityEditorHelper

MissingReferencesUnity

Unity3D-ExtendedEditor

商厦里面:

TUTBeautyUnityUnityDependencyBy

 

 

10.项目运营

图片 51

 

  • 电动构建
-   版本号——主版本号.特性版本号.修正版本号.构建版本号


    -   \[构建版本号\]应用分发平台升级判断基准


-    自动构建


    -   Android

    -   iOS
        — XUPorter 

   

 公司内部接入SODA即可,提出搭建自己的构建机,开发期间每一日N
Build排队会死人的,此外也得以搭建自己的搭建构建平台

 

  • 总结报告
-   Tlog上报


    -   玩家转化关键步骤统计(重要)

    -   Ping统计上报

    -   游戏业务的统计上报(例如桌球球局相关的统计上报)


-    灯塔自定义上报

 

  • 运营模板
-   配置化

-   服务器动态下发

-   CDN拉取图片并缓存

 

图片 52

上线前的checklist

项目

要点

说明

指标

灯塔上报

1. 灯塔自带统计信息
2. 自定义信息上报

灯塔里面包含很多统计数据,需要检查是否ok

1. 版本/渠道分布
2. 使用频率统计
3. 留存统计(1天留存、3天留存、7天留存、14天留存)
4. 用户结构统计(有效用户、沉默用户、流失用户、回流用户、升级用户、新增用户)
5. 硬件统计(机型+版本、分辨率、操作系统、内存、cpu、gpu)
6. Crash统计(Crash版本、Crash硬件、Crash次数等)
等等

信鸽推送

   

能够针对单个玩家,所有玩家推送消息

米大师支付

   

正常支付

安全组件

1. TSS组件接入
2. 隐藏内部符号表:C++开发的代码使用strip编绎选项,抹除程序的符号
3. 关键数据加密,如影子变量+异或加密算法

根据安全中心提供的文档完成所有项

接入安全组件,并通过安全中心的验收

稳定性

crash率

用户crash率:发生CRASH的用户数/使用用户数
启动crash率:启动5S内发生crash用户数/使用用户数

低于3%

弱网络

 

断线重连考虑,缓存消息,重发机制等等

客户端的核心场景必须有断线重连机制,并在有网络抖动、延时、丢包的网络场景下,客户端需达到以下要求:
一. 不能出现以下现象:
1、游戏中不能出现收支不等、客户端卡死/崩溃等异常情况;
2、游戏核心功能(如登录、单局、支付等)不能有导致游戏无法正常进行的UI、交互问题;
3、不能有损害玩家利益或可被玩家额外获利的问题;
4、需要有合理的重连机制,避免每次重连都返回到登录界面。
二. 需要对延时的情况有相应的提示

兼容性

   

通过适配测试

游戏更新

1. 整包更新
2. 增量更新

 

特别说明:iOS送审版本支持连特定环境,与正式环境区别开,需要通过服务器开关控制

性能

内存、CPU、帧率、流量、安装包大小

 

【内存占用要求】
Android平台:在对应档次客户端最低配置以上,均需满足以下内存消耗指标(PSS):
1档机型指标:最高PSS<=300MB (PSS高于这个标准会影响28%用户的体验,约1800万)
2档机型指标:最高PSS<=200MB(PSS高于这个标准会影响45%用户的体验,约3000万)
3档机型指标:最高PSS<=150MB(PSS高于这个标准会影响27%用户的体验,约1800万)
iOS平台:在对应档次客户端最低配置以上,均需满足以下内存消耗指标(PSS):
1档机型指标:消耗内存(real mem)不大于250MB(高于这个标准会影响53%用户的体验,约1900万)
2档机型指标:消耗内存(real mem)不大于200MB(高于这个标准会影响47%用户的体验,约1700万)
【CPU占用要求】
Android平台:CPU占用(90%)小于60%
iOS平台:CPU占用(90%)小于80%
【帧率要求】
1档机型(CPU为四核1.4GHZ,RAM为2G)或以上机型:游戏核心玩法中,最小FPS应不小于25帧/秒
2档机型(CPU为两核1.1GHZ,RAM为768M)或以上机型:游戏核心玩法中,最小FPS应不小于25帧/秒
3档机型(CPU为1GHZ,RAM为768M)或以上机型:游戏核心玩法中,最小FPS应不小于18帧/秒
【流量消耗要求】
游戏核心玩法流量消耗情况(非一次性消耗)应满足以下条件:
1.对于分局的游戏场景,单局消耗流量不超过200KB
2.对于不分局游戏场景或流量与局时有关的场景,10分钟消耗流量不超过500KB

 

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图