createjs 精灵图片神奇宝贝最大的精灵支持多少帧

分享到微信朋友圈
课程进度:0%
正在学习:
选课人数:1803
课程等级:初学者
课程分类:HTML5开发
课程价格:¥273
促销价格:¥218
《HTML5 全套视频教程》是优才网联合录制的一套完整的HTML5 视频教程,涉及了HTML5 开发的方方面面,包括HTML5,JS,CSS基础,也包括了HTML5 的功能特性,以及其在移动开发中的应用。最后也提供了实战的例子来巩固所学的内容。
第一章 认识HTML5
什么是HTML5 (00:16:15)
HTML5能够做什么 (00:12:17)
为什么学HTML5 (00:08:13)
怎么学好HTML5 (00:20:42)
第二章 HTML基础
语法 (00:10:10)
标题 (00:07:07)
段落 (00:05:23)
格式化 (00:09:17)
CSS样式 (00:11:23)
链接 (00:13:11)
图片 (00:09:47)
表格 (00:10:10)
列表 (00:04:33)
HTML元素 (00:08:22)
布局 (00:11:59)
表单+PHP开发环境配置 (00:40:44)
框架 (00:12:19)
颜色 (00:12:23)
实体 (00:04:06)
第三章 CSS基础
CSS语法 (00:42:46)
背景 (00:08:00)
文本和字体 (00:14:52)
列表 (00:06:42)
表格 (00:09:09)
CSS盒子模型 (00:07:01)
CSS定位 (00:16:59)
第四章 JavaScript基础
JS语法 (00:20:57)
定时器 (00:16:18)
判断语句 (00:18:43)
循环 (00:08:46)
事件 (00:13:10)
js修改css样式 (00:14:43)
异常处理 (00:03:44)
JS面向对象编程 (00:10:52)
JS内置对象 (00:17:52)
JS浏览器对象 (00:17:21)
JS DOM对象 (00:08:30)
第五章 HTML5 基础
音频 (00:23:09)
视频 (00:10:59)
拖放 (00:36:07)
Canvas (00:21:42)
SVG (00:08:52)
WebStorage (00:14:56)
应用缓存 (00:08:34)
Web Worker (00:15:20)
服务器发送事件 (00:29:34)
第六章 jQuery 基础
jQuery介绍 (00:19:12)
选择器 (00:04:55)
事件 (00:56:03)
效果 (00:30:20)
jQuery CSS (00:13:26)
jQuery AJAX (00:31:04)
扩展jQuery (00:08:44)
第七章 jQuery UI用户交互
jQuery UI 介绍 (00:11:26)
拖放 (00:09:21)
改变大小 (00:03:46)
选择 (00:11:00)
Accordion组件 (00:04:37)
Autocomplete组件 (00:07:55)
Button组件 (00:04:09)
Datepicker组件 (00:02:50)
Dialog组件 (00:16:39)
Progressbar组件 (00:07:33)
Menu组件 (00:17:32)
Slider组件 (00:09:49)
Spinner组件 (00:06:27)
Tabs组件 (00:05:44)
Tooltip组件 (00:10:02)
第八章 jQuery Moble
开发移动平台应用程序 (00:29:31)
使用在线的jQuery Moble设计器 (00:10:22)
页面和对话框 (00:23:20)
列表 (00:08:35)
Nav Bar组件 (00:07:18)
第九章 HTML5程序本地化(PhoneGap)
PhoneGap环境配置 (00:07:34)
将HTML5程序本地化 (00:13:49)
使用jQuery Mobile框架 (00:08:55)
系统事件 (00:08:08)
设备信息 (00:14:11)
网络连接状态 (00:08:04)
系统通知 (00:23:35)
加速度传感器 (00:10:58)
指南针 (00:05:41)
获取通讯录信息 (00:36:05)
数据存储 (00:42:38)
本机文件系统相关操作 (01:20:50)
开发PhoneGap插件 (00:56:32)
用HTML5程序赚钱 (00:21:12)
第十章 使用Canvas
Canvas介绍 (00:13:26)
绘制形状 (00:20:10)
简易画板 (00:12:18)
绘制图片 (00:05:12)
动画实现 (00:26:31)
第十一章 CreateJS框架
CreateJS简介 (00:08:11)
Stage (00:07:19)
显示对象 (00:16:40)
容器 (00:25:01)
Bitmap (00:06:31)
SpriteSheet帧动画 (00:15:35)
MovieClip (00:18:22)
第十二章 游戏实例
卡片记忆游戏 (00:55:24)
拼图游戏第一部分 (00:52:19)
拼图游戏第二部分 (00:26:44)
正在努力加载中
该课程暂无评价
正在努力加载中
在职课程:简老师
就业课程:史老师
周一至周日 9:00-21:00
400-058-0010cocos2d-js 和 createjs 性能对比(HTML5)-爱编程
cocos2d-js 和 createjs 性能对比(HTML5)
cocos2d-js除了做native游戏外,还可以用来做HTML5游戏/动画,那么它跟adobe的createjs框架比较会怎么样呢?
(背景知识:createjs是adobe支持的HTML5框架,沿用了Flash的思想,实现了最基本的显示列表和事件机制,是一个非常轻量的框架。createjs暂时只有canvas 2d版本,webgl版本还没完成。)
1背景,上排5个小人播放SpriteSheet动画(14帧位图轮播),下排5个小人不断做旋转和缩放。其中小人是带透明的png,尺寸为85*121px。
在PC的chrome运行,cocos2d-js和createjs都能满帧60fps,轻松搞掂无压力。
cocos2d-js:
for (var i = 0; i & 5; i++) {
var man = new cc.Sprite("res/grossini.png");
man.runAction(cc.spawn(cc.rotateBy(1, 360, 360), cc.sequence(cc.scaleTo(1, 2), cc.scaleTo(1, 1))).repeatForever());
this.addChild(man, 2);
man.x = size.width/6*(i+1);
man.y = size.height/5;
for (var j = 0; j & 5; j++) {
var man = new cc.Sprite();
var animation = new cc.Animation();
for (var i = 1; i &= 14; i++) {
animation.addSpriteFrameWithFile("res/grossini_dance_" + (i & 10 ? ("0" + i) : i) + ".png");
animation.setDelayPerUnit(1 / 7);
man.runAction(cc.animate(animation).repeatForever());
man.x = size.width/6*(j+1);
man.y = size.height / 3 * 2;
this.addChild(man, 3);
createjs:
for (var i = 0; i & 5; i++) {
var man = new createjs.Bitmap("../res/grossini.png");
man.regX = 42;
man.regY = 60;
man.x = canvas.width/6*(i+1);
man.y = canvas.height/5*4;
man.scaleX = man.scaleY = 1;
stage.addChild(man);
createjs.Tween.get(man, {loop: true}, true)
.to({rotation: 360, scaleX:2, scaleY:2}, 1000).to({rotation: 360, scaleX:1, scaleY:1}, 1000);
var images = [];
for (var i = 1; i &= 14; i++) {
images.push("../res/grossini_dance_" + (i&10?("0"+i):i) + ".png");
for (var j = 0; j & 5; j++) {
var sheet = new createjs.SpriteSheet({
images: images,
frames: {width: 85, height: 121, regX: 42, regY: 60}
}); //需要设置每帧的宽高,注册点信息
var man = new createjs.Sprite(sheet);
man.framerate = 60/7;
man.x = canvas.width/6*(j+1);
man.y = canvas.height / 3;
man.play();
stage.addChild(man);
由于播放帧动画都需要不断的替换贴图,是否使用GPU加速差别不大,所以接下来只使用旋转放缩来测试两个框架的效率区别。
基于实验一,改为使用2个图,每个图新建2000个实例放到舞台上,分别做旋转放缩的缓动变化。实验二继续在PC的chrome中运行。
cocos2d-js:使用webGL,帧频不断变化,最高有55fps,最低只有29fps。
如果让cocos2d-js强制在canvas 2d模式下渲染,帧频只有26fps左右。
createjs:使用canvas 2d渲染,保持在28fps。
在这个实验中,两者差异的原因主要是cocos2d-js使用了webgl渲染,可以让部分矩阵计算放到GPU,而createjs使用纯canvas 2d渲染,只能依赖CPU计算矩阵变换,导致每帧的计算超过了重绘时间间隔,导致了帧频降低。
接着,我们再做一个手机canvas的实验,测试机是小米1 Android 2.3,可谓是低端情况的canvas 2d,代表了一大批山寨机水平吧。
判断当前帧频,如果帧频大于30,则添加20个运动的小人到舞台上,直到帧频低于30才停止。
cocos2d-js在UC浏览器上运行,勉强支撑40个小人,帧频13到23fps之间波动。
createjs情况就没有在PC chrome那么风光了,运行20个小人就已经卡得掉牙了,只有10到15fps。
通过这个实验可以发现,手机的canvas性能真心不行,包括UC浏览器和微信内嵌的浏览器。这可能是手机CPU性能带来的主要瓶颈吧,所以在手机上只能多依赖GPU,要么发布为native,要么只给iOS 8(带webgl)的高帅富使用。
有兴趣的朋友,可以拿起手机扫一下,看看你的手机测试情况如何,跟个贴。
cocos2d-js:
createjs:
总体来说,由于cocos2d-js可以在webgl上渲染,所以性能会比createjs要好。单纯比较在canvas 2d上的渲染来说,createjs和cocos2d-js不相伯仲,没太大区别,尤其在手机(Android)上基本都是废物,手机的canvas2d游戏/动画只能尽量避免全屏重绘,减少每帧的变化。
再考虑框架的附加能力方面,cocos2d-js框架提供的UI编辑器、粒子系统、骨骼动画、瓦片地图等等,都是createjs这个轻量级选手不具备的,createjs只能从零开始,一切都得靠开发者自行实现。因此,cocos2d-js更适合做中大型游戏(大型指的是游戏画面复杂程度,而不是渲染要求高),而createjs更适合做小游戏,例如神经猫级别。
本文的代码可以在/kenkozheng/cocos/cocos_vs_createjs中找到。
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。1091人阅读
HTML5(12)
个人原创,欢迎转载,转载请注明出处&
EaselJS 动画
本节将介绍创建图形动画,精灵表位图动画,DOM元素动画.
例子1 图形动画
&!DOCTYPE html&
&meta charset=&gbk&&
&script type=&text/javascript& src=&easeljs-0.6.0.min.js&&&/script&
&canvas id=&myCanvas& width=&200& height=&200&&
你的浏览器不支持canvas标签
var myCanvas=document.getElementById(&myCanvas&);
var stage=new createjs.Stage(myCanvas);
var shape=new createjs.Shape();
shape.graphics.beginFill(&red&).drawRect(0,0,50,50);
createjs.Ticker.addEventListener(&tick&,tick);
function tick(event){
if(shape.x&stage.canvas.width){
shape.x=0;
shape.x++;
stage.update();
stage.addChild(shape);
stage.update();
shape.graphics.beginFill(&red&).drawRect(0,0,50,50);
createjs.Ticker.addEventListener(&tick&,tick);
增加时间监听器,每隔一定时间执行,参数一为事件类型,参数二为相应回调函数.
if(shape.x&stage.canvas.width){
shape.x=0;
如果shape的x坐标大于canvas标签宽度则回到原处.
shape.x++;
shape的x坐标加1(向右移动).
例子2 精灵表位图动画
&!DOCTYPE html&
&meta charset=&gbk&&
&script type=&text/javascript& src=&easeljs-0.6.0.min.js&&&/script&
&canvas id=&myCanvas& width=&800& height=&200&&&/canvas&
var myCanvas=document.getElementById(&myCanvas&);
var stage=new createjs.Stage(myCanvas);
var data={
&animations&:
&all&: [0, 25],
&images&: [&test.png&],
&height&: 256,
&width&:128,
&regX&: 0,
&regY&: 0,
&count&: 26
var spriteSheet = new createjs.SpriteSheet(data);
var bitmapAnimation = new createjs.BitmapAnimation(spriteSheet);
bitmapAnimation.x = 0;
bitmapAnimation.y = 20;
bitmapAnimation.gotoAndPlay(&all&);
stage.addChild(bitmapAnimation);
createjs.Ticker.setFPS(24);
createjs.Ticker.addEventListener(&tick&, stage);
bitmapAnimation.addEventListener(&tick&, tickEvent);
function tickEvent(event){
if(bitmapAnimation.x&stage.canvas.width){
bitmapAnimation.x=0;
bitmapAnimation.x+=5;
var data={
&animations&:
&all&: [0, 25],
&images&: [&test.png&],
&height&: 256,
&width&:128,
&regX&: 0,
&regY&: 0,
&count&: 26
创建SpriteSheet数据,animations包含动画集合,frames包含帧相关属性,images包含图片数据.test.png为以下图片,另存为即可.
var spriteSheet = new createjs.SpriteSheet(data);
创建SpriteSheet对象,参数一为SpriteSheet数据.
var bitmapAnimation = new createjs.BitmapAnimation(spriteSheet);
创建BitmapAnimation对象,参数一为SpriteSheet对象.
bitmapAnimation.gotoAndPlay(&all&);
跳到&all&并开始播放,参数一为位置标记或帧位置.
createjs.Ticker.setFPS(24);
设置每秒帧数为24.
bitmapAnimation.addEventListener(&tick&, tickEvent);
增加tick事件监听.
例子3 DOM元素动画
&!DOCTYPE html&
&meta charset=&gbk&&
&script type=&text/javascript& src=&easeljs-0.6.0.min.js&&&/script&
text-align:
background-color: #000;
color:#FFF;
height:250
&div class=&canvasHolder&&
&div id=&content&&
&h2&例子3 DOM网页元素动画&/h2&
小芽教程,冰灵制作&br/&
个人原创,欢迎转载,转载请注明出处&br/&&br/&
&a href=&http://blog.csdn.net/bud_icelf&&http://blog.csdn.net/bud_icelf&/a&&br/&&br/&
QQ:&br/&&br/&
&button width=&100& onclick=&alert('小芽教程,冰灵制作')&&测试按钮&/button&
&canvas id=&myCanvas& width=&400& height=&250&&&/canvas&
var myCanvas=document.getElementById(&myCanvas&);
var stage=new createjs.Stage(myCanvas);
var myCanvas=document.getElementById(&content&);
var dOMElement = new createjs.DOMElement(content);
dOMElement.regX=400;
dOMElement.regY=250;
dOMElement.x=400;
dOMElement.y=250;
stage.addChild(dOMElement);
createjs.Ticker.addEventListener(&tick&, tick);
function tick(event){
if(dOMElement.x&document.body.clientWidth){
dOMElement.x+=3;
stage.update();
var myCanvas=document.getElementById(&content&)
获取id为content的div元素.
var dOMElement = new createjs.DOMElement(content);
创建DOMElement对象,参数一为DOM元素.
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:10690次
排名:千里之外
原创:16篇最火HTML5 JavaScript游戏引擎:国外篇(二)
发表于 15:50|
作者唐小引
摘要:在3D当道2D逆袭的今天,HTML5和JavaScript游戏引擎逐渐走向了成熟,在追求原生体验的同时,也深逐精致细腻狂炫酷拽。在本文中,我们将继续介绍来自国外,非常受开发者欢迎的HTML5和JavaScript游戏引擎。
6. Gogo Make Play(简称为GMP)是一款快速且免费的开源JavaScript游戏引擎,基于MIT和GPLv2许可协议发布,其所有代码可登陆GMP官网下载。GMP诞生于2006年12月,其开发者为来自加拿大温哥华的软件开发者Trevor Cowley。GMP最初是Trevor一款基于浏览器的弹球游戏的后端代码,后逐渐发展成为一个独立的引擎。GMP体积小,操作简单,非常易于学习和使用,开发者只需掌握简单的HTML/JS/CSS,就可以通过Web浏览器来构建和管理HTML页面,GMP拥有完整的API文档以及用户手册和教程,在未来,Trevor还将推出一系列的插件和游戏组件模板,以帮助开发者更方便容易地进行游戏开发。相关链接:Gogo Make Play的、7. CreateJS是一款可以构建丰富交互体验的HTML5游戏开发框架,由Flash达人Gskinner开发,Adobe、微软和AOL官方赞助,并已托管到GitHub上。CreateJS大部分API都是基于Flash原有的API来模仿实现的,并且官方提供了直接把Flash动画转成JS数据包的工具,调用起来很方便。CreateJS提供了若干开发套件及工具,分别是:EaselJS(负责图形、事件、触控、滤镜等功能)、TweenJS(补间动画)、SoundJS(音频控制)、PreloadJS(文件加载)和Zo?(生成图片精灵及动画数据)。主要优点:Flash开发者很容易上手;提供了Flash转HTML5的工具,可以将部分Flash代码进行转换再修改;基于MIT协议的开源框架;类库设计非常独立,包含不同的模块,可选择性使用。相关链接:CreateJS的、8. jGen是一款开源的JavaScript游戏引擎,其开发者为来自俄罗斯莫斯科的Ruslan Matveev。jGen支持简单的精灵动画、碰撞和渲染等轴地图等功能,其目标是让开发者不使用Canvas,只需HTML和JavaScript就可以开发出基于现代浏览器的应用,目前,jGen仅支持Chrome和Safari。相关链接:jGen的、9. Pulse是一款开源的JavaScript游戏和图形引擎,由Modulus团队开发,成员包括Charlie Key、Brandon Cannaday、Richard Key。Pulse为开发者提供了一个非常简单的框架,只需几行JavaScript和HTML代码就可以构建HTML5游戏。此外,Pulse还引入了插件架构,开发者可以轻松进行核心功能的扩展。相关链接:Pulse的、10. LycheeJS是一款环境独立的开源JavaScript游戏引擎,基于MIT许可协议发布,可以在任何支持JavaScript的环境中运行。LycheeJS于2012年6月面世,其理念是做最快的JavaScript游戏引擎。LycheeJS提供了CDN、WebSockets、SPDY、HTTP2.0以及游戏截图支持,可高性能运行于PC(Firefox、Chrome、Opera、Safari、IE)和移动平台(WebKit、Chrome、Firefox、Safari)浏览器之上。相关链接:LycheeJS的、系列阅读:我们搜集了国内外最火的HTML5 JavaScript游戏引擎,本系列将不断更新,也欢迎大家提供线索,请私信:,或发送邮件至mobile#csdn.net。本文为CSDN原创文章,未经允许不得转载,如需转载请联系market#csdn.net(#换成@)
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章本文主要选取了Construct2、ImactJS、LimeJS、GameMaker、CreateJS、lycheeJS、Crafty、three.js、melonJS、Turbulenz、Quintus、Cocos2d-html5等进行了简要介绍和对比,主要是根据网上的资料整理而成。
主流框架对比
Construct2
Construct 2是一个运行于Windows平台的游戏制作工具,它可以让没有任何编程基础的用户在短时间内不写一行代码快速开发出一款可运行于所有平台(Windows、Mac、Linux、Android、iOS等)的游戏。免费版可以将游戏导出成HTML5。收费版本分为个人版(79英镑)和企业版(259英镑),可以导出所有平台的版本,同时提供了更多的特效和音乐。如果使用该工具盈利超过5000美元,需要升级到企业版。
1. 简单易用,可实时运行游戏
2. 强大的事件系统,可以不通过写代码来控制游戏逻辑
3. 提供了可编程扩展的接口
4. 提供了大量特效,支持物理效果
5. 支持所有平台
6. 完整的文档以及社区支持
不如直接写代码灵活
参考资料:
ImpactJS是一个基于JavaScript的HTML5游戏引擎,同时支持PC和移动平台浏览器。它是目前除了Construct2之外最受欢迎的HTML5游戏引擎,使用需要支付99美元。
1. 提供了灵活的关卡编辑器,可以快速构建游戏地图
2. 提供了强大的调试工具
3. 提供了Ejecta可以将JavaScript的执行结果通过OpenGL渲染出来,可以在iOS平台上获得与原生应用相近的效率
4. 文档齐全,有两本专门介绍ImpactJS开发的书
5. 支持物理效果
6. 支持自己编写插件来扩展
App Store游戏
LimeJS是一个基于Google Closure Library开发的HTML5游戏框架,继承了Closure代码易读易懂、架构清楚的特性。同时提供了游戏中各种通用实体的封装,如Director、Scene、Layer、Event和Animation等,与Cocos2d的API类似。它是由公司创建。
1. 基于Apache协议的开源框架
2. 功能强大,文档齐全,与ImactJS类似
3. 支持物理效果
4. 与Cocos2d的API类似,容易上手
依赖于Google Closure
GameMaker与Construct 2类似,都是一个游戏制作工具,可以导出到各个平台运行,分为免费版、标准版(49.99美元)、专业版(99.99美元)和大师版(799.99美元)。其中免费版只能导出Mac和Windows版本,导出HTML5需要大师版或者专业版(再额外支付99.99美元)。
优点和缺点:
优势与Construct2类似,但性价比不如Construct2高
CreateJS(EaselJS)
CreateJS是Adobe官方赞助的开源开发框架,它大部分API都是基于Flash原有的API来模仿实现的,并且官方提供了直接把Flash动画转成JS数据包的工具,调用起来很方便。CreateJS提供了若干开发套件及工具,分别是:EaselJS(负责图形、事件、触控、滤镜等功能)、TweenJS(补间动画)、SoundJS(音频控制)、PreloadJS(文件加载)和Zo?(生成图片精灵及动画数据)。
1. Flash开发者很容易上手
2. 提供了Flash转html5的工具,可以将部分Flash代码进行转换再修改
3. 基于MIT协议的开源框架
4. 类库设计非常独立,包含不同的模块,可选择性使用
lycheeJS是一个环境独立的JavaScript游戏引擎,可以在任何支持JavaScript的环境中运行。它的理念是做最快的JavaScript游戏引擎。
1. 同时支持PC(Firefox、Chrome、Opera、Safari、IE)和移动平台(WebKit、Chrome、Firefox、Safari)的浏览器
2. 提供了CDN、WebSockets、SPDY、HTTP2.0以及游戏截图的支持
3. 提供了可以直接导出第三方(Facebook、AppStore、Google Play Store)资源包来发布
4. 基于MIT协议的开源框架
Crafty是一个体积小、简单、轻量级的2D的HTML5游戏引擎,它提供了通过Canvas或DOM来绘制实体,提供了精灵Map以及SAT高级碰撞监测支持。它是由个人(Louis Stowasser)创建,同时由Github上的一些开发者共同开发。
2. 轻量级引擎,不会受到框架的太多束缚
3. 同时支持PC和移动平台浏览器
Three.js是一个轻量级的JavaScript库,用于在浏览器上创建和显示3D图形。它可以同时使用Canvas、SVG或WebGL进行绘制。
优点和缺点:
支持3D,但是不适合做2D游戏
melonJS是melonJS团队对Javascript热情以及开发经验的结晶,是一个简单、免费、而且独立的类库。
1. 轻量级的2D引擎
2. 支持所有主流的PC和移动平台浏览器
3. 支持使用Tiled map editor来创建和编辑地图
4. 支持多声道音频
5. 基于MIT协议的开源框架
Turbulenz是一个开源的HTML5游戏引擎,提供了可以运行在Windows、MacOS、Linux上的SDK,允许开发人员创建高质量和硬件加速的2D、3D游戏。包括以下功能:异步资源加载、进行特效和粒子渲染、支持物理效果、碰撞检测以及动画、3D音效支持、支持网络交互以及社交网络分享、场景和资源的管理。
1. 功能强大,同时支持2D和3D
2. 基于MIT协议的开源引擎
Quintus是一个容易上手、轻量级、且模块化的HTML5游戏引擎。它引用面向对象的思想来进行HTML5游戏开发,同时依赖于jQuery来提供事件处理机制和元素选取操作。
1. 依赖于jQuery
2. 目前引擎仍处于初级阶段,还很不成熟
Cocos2d-html5
Cocos2d-html5是一款基于Cocos2d-x API的2D开源免费HTML5游戏引擎。它目前通过canvas进行渲染,将来会支持WebGL。它由国内Cocos2d-x核心团队主导开发和维护,行业领袖、HTML5大力推动者Google为这个项目提供支持。同时,Zynga、Google等大公司的工程师也参与到它的设计工作中。
1. 与Cocos2d的API类似,容易上手
2. 中文文档齐全,资料丰富
3. 基于MIT协议的开源引擎
各框架具体参数对比
1. 各HTML5游戏框架对比
3. 对于Crafty、Lime、Frozen、Melon、Impact、Quintus框架,可以在上查看用这些引擎开发同一个游戏的效果以及代码风格。Breakouts中使用到的特性包括碰撞检测、精灵动画、音效、地图、场景切换、交互、文字渲染、移动平台支持。
4. 以上各引擎中,除了Construct2、ImpactJS、GameMaker是收费的之外,其他引擎都是免费并且开源的。对于开源引擎,我们可以从Github上面的关注度了解到该引擎的流行程度,关注的人越多,遇到问题越容易解决。同时一般来说,项目开发者越多,版本更新越快;项目的进行时间越长则越成熟。下面将对各开源引擎的开发者人数、项目启动时间、关注度进行对比。
Game Engine
Github commits
Github contributors
Start time
Github Star
Github Fork
(最近才开源)
Cocos2d-html5
以上各引擎中,Construct2、ImpactJS、GameMaker三个是收费的,其中Construct2与GameMaker更像一个游戏开发工具,可以实现不用写一行代码来制作游戏,更适合于没有编程基础的人使用。而ImpactJS作为一个高质量的框架,且易于扩展,虽然是收费的,但是物有所值。
开源引擎中,three.js是最火的,但是仅限于开发3D游戏。其次是CreateJS,由Adobe官方赞助且采用Flash类似的API以及模块化开发,是Flash开发者以及将Flash游戏转换成html5不可多得的选择。Turbulenz虽然开源时间比较晚,但颇有后来者居上的趋势,由于其对2D和3D的同时支持,是同时开发2D和3D游戏的最佳选择。LimeJS与Crafty相比的优势在于有一个公司进行维护,相比个人要更稳定,但是需要依赖于Google Closure,也使之成为一个重量级的框架。Crafty体积小、轻量级,更适合于小游戏的开发。Cocos2d-html5作为国产框架的一个优势在于中文文档和教程多,且得到了Google的支持,但相比ImpactJS、CreateJS仍不够成熟。melonJS、Quintus、lycheeJS的开发者和使用者都较少,相关文档和教程也相对少,还有待观察。
如果大家觉得对自己有帮助的话,还希望能帮顶一下,谢谢:)
个人博客:
本文地址:
转载请注明出处,谢谢!
日 英超 赛季
日 西甲 赛季
日 德甲 赛季
日 意甲 赛季
日 法甲 赛季
1、查看 keystore
$ keytool -list -keystore debug.keystore
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
androiddebugkey, Mar 21, 2013, PrivateKeyEntry,
Certificate fingerprint (MD5): E0:F4:90:EE:CD:77:17:0E:B8:C4:AC:64:B2:F6:FC:83
2、查看三方应用或是系统应用签名
用winrar打开待查看的apk,将其中META-INF文件夹解压出来,得到其中的CERT.RSA文件
$ keytool -printcert -file META-INF/CERT.RSA
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 514ab2e1
Valid from: Thu Mar 21 15:12:33 CST 2013 until: Sat Mar 14 15:12:33 CST 2043
Certificate fingerprints:
E0:F4:90:EE:CD:77:17:0E:B8:C4:AC:64:B2:F6:FC:83
SHA1: 7F:E5:11:D8:37:4F:DA:D7:75:EA:A5:8C:47:06:85:95:6D:1D:3F:2B
Signature algorithm name: SHA1withRSA
Version: 3
3、给空白包签名
jarsigner -verbose -keystore [keystorePath] -signedjar [apkOut] [apkIn] [alias]
jarsigner命令格式:-verbose输出详细信息 -keystore密钥库位置 -signedjar要生成的文件 要签名的文件 密钥库文件
keystorePath参数代表keyStore的绝对路径,如D:\keystore
apkOut参数代表签名后的apk路径,如D:\signed.apk
apkin参数代表在腾讯应用中心下载的未签名apk,默认名称为tap_unsign.apk
alias参数代表签名用的alias名称(创建keyStore时所填写),如timdong
$ jarsigner -verbose -keystore debug.keystore -signedjar test2.apk tap_unsign1.apk timdong
Enter Passphrase for keystore:
adding: META-INF/MANIFEST.MF
adding: META-INF/ANDROIDD.SF
adding: META-INF/ANDROIDD.RSA
signing: res/drawable/ic_launcher.png
signing: res/layout/main.xml
signing: AndroidManifest.xml
signing: resources.arsc
signing: classes.dex
本文介绍了.net 版的一个HTMLParser网页解析开源类库(Winista.HTMLParser)的功能特性、工作原理和使用方法。对于使用.net进行Web信息提取的开发人员进行了一次HTMLParser的初步讲解。应用实例将会在日后的文中介绍,敬请关注。一、背景知识
HTMLParser原本是一个在sourceforge上的一个Java开源项目,使用这个Java类库可以用来线性地或嵌套地解析HTML文本。他的功能强大和开源等特性吸引了大量Web信息提取的工作者。然而,许多.net开发者朋友一直在寻找一种能在.net中使用的HTMLParser类库,笔者将介绍Winista.HTMLParser类库,对比于其他原本数量就非常少的.net版HTMLParser类库,Winista的版本的类库结构可以说更接近于原始Java版本。
该类库目前分为Utltimate、Pro、Lite和Community四个版本,前三个版本都是收费的。只有Community版本可以免费下载并查看所有的源码。
该版本的。
二、功能和特性
1.可以在任何.net语言中使用(C#,VB.net,J#等)
2.可以解析几乎所有的Html标签,并且可以通过标签类别、属性或正则表达式来搜索标签。有些甚至在Java版本中无法支持的标签也在这个版本中得到了支持。
3.设置可扩展的过滤器来过滤结果集中不需要的标签。
4.高性能的API接口使得你能处理许多常见的问题,如:哪些是页面中的外部链接?哪些是图片?哪些是不同的表格?页面中有错误的链接吗等等问题。
5.一个基于Http协议引擎的配置文件使得你能通过一个指定的URL地址来获得该页面内容。该爬虫可以遵循robot.txt协议文件来获得组织和允许访问的列表。
6.Http协议引擎能够完整地处理来自任何站点的反馈。
三、词法分析的工作原理
HTMLParser的词法分析器对HTML进行了4级封装,从低级到高级的顺序为:ParserStream、Source、Page、Lexer。ParserStream负责从文件中获取二进制数据,但不做任何处理。Source把二进制文件转换成相应的字符序列,存储一组未加工的字符序列。Page可以看成是一个string数组,按行存储一个Source文本的每一行第一个字符开始的位置索引。Lexer包含了词法分析的代码,从Page里读取字符串,用Cursor记录当前字符所在位置,通过状态机来生成Nodes节点。
Lexer中真正执行词法分析的是NextCode()方法,它每次词都查找返回下一个Node节点,直到Page结束。算法描述如下:
1.读入一个字符,判断是否已是页尾,是则返回null。
2.判断是否是”&“,如果是,则可能是标签入口,需读取下一字符确认。
3.如果都不是,ParserString状态机开始解析一个StringNode,如果是”&“,继续读取下一字符。
4.判断是否到页尾,是则产生一个StringNode返回。
5.如果读取到”%”,则说明是JSP标签,进入JSP状态机去解析。
6.如果读取到”?”,则说明是XML标签,进入XML状态机去解析。
7.如果读取到”/”或任何字母,说明是Tag标签,进入Tag标签状态机去解析。
8.如果读取到”!”,则说明进入了一个注释标签,需要再读取一个字符,如果到页尾,则产生一个StringNode返回,如果字符为”&”则生成一个RemarkNode返回,否则
回退一个字符,再判断字符如果是”-“则回退一个字符,进入Remark状态机去解析,如果不是,则回退一个字符进入Tag状态机去解析。
四、三种使用方法的比较
1.使用Lexer词法分析器直接解析HTML。
这样的方法较为底层,只能返回一个线性的Node节点序列,通过Lexer.NextNode()方法获得下一个Node的信息。虽然不够方便,但有时可完成一些较为灵活的工作。
调用的方法是(传入string类型的html代码):
Lexer lexer = new Lexer(htmlcode);
INode node = lexer.NextNode();
Console.Write(node.ToString());
返回结果是该页面的第一个标签”html”的Node结点信息。
2.使用Filter结点过滤模式。
如果你有一些很明确的结点需要提取,那么就该使用Filter结点过滤模式。系统定义了17种具体的Filter,根据不同的过滤条件来获得需要的结点。包括依据结点父子关系的Filter,连接Filter组合的Filter,依据网页内容匹配情况的filter,等等。我们也可以继承 Filter做自己的Filter来提取节点。
NodeList nodeList = myParser.parse(someFilter);
解析之后,我们可以采用:
INode[] nodes = nodeList.toNodeArray();
来获取节点数组,也可以直接访问:
INode node = nodeList.elementAt(i);
来获取Node。
另外,在Filter后得到NodeList以后,我们仍然可以使用nodeList.extractAllNodesThatMatch(someFilter)来进一步过滤,同时又可以用nodeList.visitAllNodesWith(someVisitor)来做进一步的访问。
3.使用Visitor结点访问模式
如果你希望HTMLParser遍历所有的结点,并按结点的不同类型(StringNode、RemarkNode、TagNode)和不同的访问过程来进行不同操作的话,可以使用Visitor模式。NodeVisitor是一个抽象类,分别定义了如下方法:
BeginParsing():解析前进行的操作
VitisTag():访问到开始标签时的操作
VisitEndTag():访问到结束标签时的操作
VisitStringNode():访问到文本结点时的操作
VisitRemarkNode():访问注释结点时的操作
自己定义一个类并继承NodeVisitor类,实现以上几个方法,即完成Visitor模式的访问类。系统也提供了7个具体的结点访问类,具体见上文提供的类库文档。不过这7个类并不实用,大多数的功能还需要自己来扩充定义。调用方法:
Parser parser = Parser.CreateParser((htmlcode), “GBK”);//传入string类型的html代码
NodeVisitor visitor = new LinkFindingVisitor(linktext); //以链接查找的Visitor举例
parser.VisitAllNodesWith(visirot);
灵活使用以上三种模式的结合,相信就可以提取到任何我们所需要的信息了。
在搜索引擎的开发中,我们需要对网页的Html内容进行检索,难免的就需要对Html进行解析。拆分每一个节点并且获取节点间的内容。此文介绍两种C#解析Html的方法。
第一种方法:
用System.Net.WebClient下载Web Page存到本地文件或者String中,用正则表达式来分析。这个方法可以用在Web Crawler等需要分析很多Web Page的应用中。
估计这也是大家最直接,最容易想到的一个方法。
转自网上的一个实例:所有的href都抽取出来:
一些爬虫的HTML解析中也是用的类似的方法。
第二种方法:
利用Winista.Htmlparser.Net 解析Html。这是.NET平台下解析Html的开源代码,网上有源码下载,百度一下就能搜到,这里就不提供了。并且有英文的帮助文档。找不到的留下邮箱。
个人认为这是.net平台下解析html不错的解决方案,基本上能够满足我们对html的解析工作。
自己做了个实例:
using System.Collections.G
using System.D
using System.D
using System.L
using System.T
using System.Windows.F
using Winista.Text.HtmlP
using Winista.Text.HtmlParser.L
using Winista.Text.HtmlParser.U
using Winista.Text.HtmlParser.T
using Winista.Text.HtmlParser.F
namespace HTMLParser
public partial class Form1 : Form
public Form1()
InitializeComponent();
private void btnParser_Click(object sender, EventArgs e)
#region 获得网页的html
txtHtmlWhole.Text = “”;
string url = CBUrl.SelectedItem.ToString().Trim();
System.Net.WebClient aWebClient = new System.Net.WebClient();
aWebClient.Encoding = System.Text.Encoding.D
string html = aWebClient.DownloadString(url);
txtHtmlWhole.Text =
catch (Exception ex)
MessageBox.Show(ex.Message);
#endregion
#region 分析网页html节点
Lexer lexer = new Lexer(this.txtHtmlWhole.Text);
Parser parser = new Parser(lexer);
NodeList htmlNodes = parser.Parse(null);
this.treeView1.Nodes.Clear();
this.treeView1.Nodes.Add(“root”);
TreeNode treeRoot = this.treeView1.Nodes[0];
for (int i = 0; i & htmlNodes.C i++)
this.RecursionHtmlNode(treeRoot, htmlNodes[i], false);
#endregion
private void RecursionHtmlNode(TreeNode treeNode, INode htmlNode, bool siblingRequired)
if (htmlNode == null || treeNode == null)
TreeNode current = treeN
//current node
if (htmlNode is ITag)
ITag tag = (htmlNode as ITag);
if (!tag.IsEndTag())
string nodeString = tag.TagN
if (tag.Attributes != null && tag.Attributes.Count & 0)
if (tag.Attributes[“ID”] != null)
nodeString = nodeString + ” { id=\”” + tag.Attributes[“ID”].ToString() + “\” }”;
if (tag.Attributes[“HREF”] != null)
nodeString = nodeString + ” { href=\”” + tag.Attributes[“HREF”].ToString() + “\” }”;
current = new TreeNode(nodeString);
treeNode.Nodes.Add(current);
//获取节点间的内容
if (htmlNode.Children != null && htmlNode.Children.Count & 0)
this.RecursionHtmlNode(current, htmlNode.FirstChild, true);
content = new TreeNode(htmlNode.FirstChild.GetText());
treeNode.Nodes.Add(content);
//the sibling nodes
if (siblingRequired)
INode sibling = htmlNode.NextS
while (sibling != null)
this.RecursionHtmlNode(treeNode, sibling, false);
sibling = sibling.NextS
private void AddUrl()
CBUrl.Items.Add(“”);
CBUrl.Items.Add(“”);
CBUrl.Items.Add(“http://www.”);
运行效果:
实现取来很容易,结合Winista.Htmlparser源码很快就可以实现想要的效果。
简单介绍了两种解析Html的方法,大家有什么其他好的方法还望指教。
Android的终端碎片化问题,是一个很讨厌的问题。
而对于国内开发者来说,Android的市场“碎片化”问题也是一个很头疼的问题。
一起先来看一段代码:
private String getChannelName(String channelKey) {
String result = “”;
if (“dev”.equals(channelKey)) { result = “开发版”;
} else if (“official”.equals(channelKey)) { result = “官方版”;
} else if (“google”.equals(channelKey)) { result = “谷歌版”;
} else if (“appchina”.equals(channelKey)) { result = “应用汇版”;
} else if (“youmi”.equals(channelKey)) { result = “有米版”;
} else if (“waps”.equals(channelKey)) { result = “万普版”;
} else if (“gfan”.equals(channelKey)) { result = “机锋版”;
} else if (.equals(channelKey)) { result = “91版”;
} else if (“hiapk”.equals(channelKey)) { result = “安卓版”;
} else if (“goapk”.equals(channelKey)) { result = “安智版”;
} else if (“mumayi”.equals(channelKey)) { result = “木蚂蚁版”;
} else if (“eoe”.equals(channelKey)) { result = “优亿版”;
} else if (“nduo”.equals(channelKey)) { result = “N多版”;
} else if (“feiliu”.equals(channelKey)) { result = “飞流版”;
} else if (“crossmo”.equals(channelKey)) { result = “十字猫版”;
} else if (“liantong”.equals(channelKey)) { result = “联通版”;
} else if (“huawei”.equals(channelKey)) { result = “智汇云版”;
} else if (“qq”.equals(channelKey)) { result = “腾讯版”;
} else if (“3g”.equals(channelKey)) { result = “3G版”;
} else if (.equals(channelKey)) { result = &#版”;
} else if (“baidu”.equals(channelKey)) { result = “百度版”;
} else if (“sohu”.equals(channelKey)) { result = “搜狐版”;
} else if (“samsung”.equals(channelKey)) { result = “三星版”;
} else if (“coolmart”.equals(channelKey)) { result = “酷派版”;
} else if (“meizu”.equals(channelKey)) { result = “魅族版”;
} else if (“moto”.equals(channelKey)) { result = “摩托版”;
} else if (“xiaomi”.equals(channelKey)) { result = “小米版”;
} else if (“lenovo”.equals(channelKey)) { result = “联想版”;
} else if (“zhuamob”.equals(channelKey)) { result = “抓猫版”;
} else if (“iandroid”.equals(channelKey)) { result = “爱卓版”;
} else if (“imobile”.equals(channelKey)) { result = “手机之家版”;
} else if (“uc”.equals(channelKey)) { result = “UC版”;
} else { result = “山寨版”;}
这还只是一部分市场,有几个是我自定义的和广告平台的,剩下的也有将近30个,第一次光是注册账号就会烦你一天的,以后每次光是上传应用就会弄晕你。1. 国内到底有哪些市场?
这是一个很难回答问题,”百密必有一疏”,所以我正好借用这个平台列举一下,通过大家慧眼识珠和强大的人肉回答来修正和补充:
// 下面主要是列出开发者后台地址
: /apps/publish
机锋市场 : /
91和安卓市场 : http://dev./
//说明一下,发布在安卓市场也会发布到91市场,他们其实同一家了
安智(goapk) : /
木蚂蚁 : /
N多网 : /developer
联想乐商店 : /developer/
十字猫 : /
腾讯应用宝 : /android/index.jsp
智汇云 : /indexManageAction.action
小米应用商店 : /
易优 : /user/login/lang/zh_CN
手机之家 : .cn
联通沃商店 : .cn/userportal/mapc_login.action
爱卓网 : /index.php?app=my_sharegoods&act=add&is_original=1
大家尽情的留言补充啊,期待大家的力量….2. 哪个市场的好坏?
这是一个很难回答问题,”圣人为圣,善假于物”,同一个平台,适合不同阶层的开发者,有些大平台可能对于个人开发者来说,上首页推荐的机会就比较小,成本比较高,而在小的平台可能性就要大些了。利用好各个平台,不要嫌弃一些小平台,这点我觉得很重要。
所以,这里不做综合比较。
我就根据友盟统计的数据来分析一下吧(因为我的应用下载量比较小,而且没有做任何推广,仅供参考):
即时新增用户
累计用户(%)
appchina64
123 784(66.0 %)
209(17.0 %)
这是我周一发布的应用的数据(我就不说名字了,避免做广告嫌疑),能反应一个大概的各市场的量的比例,当然有的市场数据明显不对,比如gfan,这个有待勘察。
我还有几个应用,也是差不多的量,没什么参考价值,就不列出来了。
欢迎各位能列出有代表的数据,我可以加到这篇文章来。3. 提交应用的准备工作
终于开始进入本文的重点了,应用开发完毕,打包好了,也签名了,是不是马上去提交!
有一条指导建议:”临时现做总是很慢的”;
OK,可以,但是一个市场两个市场可以,市场一多,你自己会先烦掉的。不如先把下面的准备工作做好的。
市场对于提交的应用一般需要填写相应的资料,需要提前就做好准备,比如第一次提交:
(1). 应用程序APK文件
(2). 应用简短描述,10个字或者20个字内
(3). 应用关键字,以空格或者逗号隔开,有的市场还会限制个数,比如最多5个
(4). 应用介绍,有的市场要大于200字,
(5). 应用icon,个人市场需要单独上传icon图标,google play上需要上传一个512×512的高清icon,最好提前准备好
(6). 应用截图,最好准备5张,一般市场要求3-5张
(7). 官方网站,这个填写博客就可以了,我想不是问题吧
(8). 宣传图,这个是可选的,个别市场上有这个选项,如google play上的尺寸要求为800×480,0,飞流上也有一个,要求224×108尺寸的
(9). 类别,下拉选择一个接近的,各个市场的分类都不大一致
第二次更新升级的时候,就会简单很多:
(1). 最新APK文件
(6). 最新截图,有些市场可以用旧的截图
(8). 最新宣传图,可选
(10). 更新日志,必选,发布之前就要整理好,[增加][修复]了哪些功能和问题
准备工作只要做一次,还算比较简单。下一步才是真正的繁琐。4. 广告平台问题
做完上面一步,你可能就要面临下面这个重大问题,广告平台问题:不同的市场对不同的广告平台有不同的兼容性。很多广告平台在一些市场几乎是不能上的,比如最典型的是,安智网是不容许积分墙的,所以万普的积分墙应用是进入不了安智市场的。
那这个问题怎么解决?
不上?不行,没有条件创造条件也要上。
这个需要在这家广告平台和这家市场之间做一个选择了。
我的解决办法是发布另外一个不包含这家广告平台的同一个应用,比如我把万普的换成有米没有积分系统的同一款应用,这样就能上传到安智市场了。
这点最好在开发早期就考虑好,从技术的角度打包不同广告平台的应用,本文就不深入探讨了。5. 正式提交应用到各大市场
上面都做好了的话,接下来,就是正式的提交应用到各大市场了。
提交应用绝对是一个任劳任怨的体力活。
在公司里面应该是有市场推广部门负责的,但是个人的话,只能亲自操刀上阵,一个一个来了。
在这个繁琐枯燥的过程中,我记录了各个市场的”脾气“,积累了一点经验,特别拿出来记录、分享,以求共勉。
(1). 应用汇appchina:
点评:应用汇是最好上的,量比较大,审核也特别快,1天左右就能上架,也没什么限制积分墙。赞一个!
详细:应用汇的量大,我初步分析不是应用汇本身的量,而是其他很多第三方网站抓取后转载导致。
(2). 安卓市场(91):
点评:安卓市场限制积分墙,一定程度的内容审查和特殊权限的控制,审核速度还行,1-2天吧,量算比较大点的。
详细:第一,安卓市场是不能上万普积分墙的,会提示不支持的积分墙的应用,不予通过。据说以前可以,但是现在不行。第二,我有一个应用里面包含了”成人用品“的内容(我认为是这个原因),结果别拒绝了,拒绝理由是”抱歉,您的软件中部分文字尺度过大,谢绝发布。安卓市场严禁张贴政治、色情、恐怖、暴力的图片及文字,感谢配合!“。第三,不允许CALL PHONE权限,拒绝理由是”抱歉,您的软件发现功能以外的额外付费权限“拨打电话”,请检查,正常功能需求,请在软件描述中注明使用功能点,感谢配合“。
(3). 机锋市场
点评:机锋市场算比较好上的,支持万普积分墙,要求不严格,审核比较快,1-2天吧,量也不错,但是升级好像没什么量。但是需要主要机锋标识,什么竞争对手链接等问题。
详细:第一,我有一次被拒绝的理由是“因为:含有竞争类产品链接,拒绝。。请修改,修改后我们会尽快再次审核。感谢合作!”,我勒了个去,莫名其妙,后来都不知道改了什么,再上传就通过了。第二,针对万普,桔子,有米等等几个广告平台,机锋市场上提交应用和其他市场有一个很大的区别是,需要增加机锋标识,可以优先上架,刚开始不知道的人还真不知道怎么弄,这里我贴出相关文档的地址:否则会被拒绝:”品不符合市场发布规范(广告 万普世纪, SDK未添加机锋标识),暂拒。。请修改“。
(4). 腾讯应用
点评:之前印象挺好的,速度快,支持万普积分墙,量也马马虎虎还行,但是现在一个应用上传了快两周了还没审核测试,搞不懂腾讯应用是不是内部出现问题了????
详细:之前审核速度相当快,我以为是大公司的,要求肯定高,但是腾讯的要求不是很严格,但是,但是,现在,11月26日升级一个应用,到现在还是”待测试“,12月2日上传一个新的应用,两三天了没动静,还是”待审核“,什么情况啊。
(5). 360应用
点评:坑爹的一个平台,左一个版权,右一个名堂,还搞黑名单,一旦是黑名单,再修改都提交不了。
详细:不说了,名堂太多。
(6). 优亿市场
点评:对于个人开发者来说,比较坑爹,需要授权证书和证明文档,如下图,和360是一路货色,打心里看不起个人开发者。(7). 木蚂蚁
点评: 比较容易上,支持万普积分墙,量个人觉得不大,审核1-2天吧,但是”不收录个人开发者提交的图书、笑话、连连看、对对碰、壁纸、锁屏类应用。“,需要注意一下,我的《幽默笑话》就被拒绝了。
(8). 3G安卓市场
点评:审核算快的,1-2天吧,量感觉还可以,支持万普积分墙。还不错。
详细:最近,也就是前几天又提交了一个应用,过了几天,3G安卓市场发来了一个邮件,说软件被下架了,原因是“(产品不通过)封面图与截图不能为同一张”,这都被发现了!!只能换图了。
(9). N多市场
点评:审核速度还可以,1天左右有反馈,不支持万普积分墙。
详细:上传第二天就被拒了,反馈倒是挺快的:”经测试您的应用不符合我们的审核标准,请检查您的应用是否含有积分系统、推荐其他应用或广告自行下载等问题。请确保您再次上传的应用不包含以上问题。“,昨天更新升级,现在还在审核中,之前上传了2款应用都审核通过了,待查。
(10). 十字猫
点评:软件刚上传,审核时间稍微长一点,2-3天吧,暂时感觉量一般!
详细:发生了一件比较搞的事情,之前十字猫我一直登陆不上,点”忘记密码“重置了好几次密码,一直提示我密码错误,非常郁闷啊,试了又试,过了几天又试,搞了很久,后来没办法联系商务,结果告诉是说我的开发者账号需要审核,汗,系统提示也太垃圾了吧,还好,商务很快就给我审核通过了。
(11). Google Play
点评:主要是账号需要信用卡申请,我是用招行双币visa信用卡办的,没什么审核,但是要填的东西蛮多的,量比较小。
详细:软件上传后详细页面生效可能要等几个小时。
(12). 联想乐商店
点评:审核速度超快,量还可以,不能上万普积分墙。
详细:可能是先自动审核,再人工干预。因为我才上传5分钟,就接到邮件通知,因为积分墙被拒绝了:================================================检测项目
描述积分墙检测结果
含有非联想指定的积分墙兼容性测试检测结果
================================================随后我马上更新上传一个不包含积分墙的版本,不到一个小时就审核通过了,邮件如下:================================================;;;; 很荣幸地通知您, 您提交的应用——xxxx将于30分钟内上架,您可以先逛逛乐商店,看看有什么好玩的应用。 也请您多关注自己应用的下载情况,并及时回复用户提出的问题,谢谢。================================================太特么高效了。
(13). 智汇云
点评:审核速度还行,2天吧,不支持万普积分墙吧,量的话一般般。
详细:华为的平台,还算比较容易上,需要身份实名认证。
(14). 魅族
点评:审核速度比较快,一天左右,支持万普积分墙,初步感觉量还可以。
详细:网上有人说魅族的量比较大,审核非常严格,我没感觉到,继续观察!!!
(15). 小米
点评:小米的审核速度也是超快,估计量一般吧,支持万普积分墙。
详细:上传应用后一会儿就反馈一封邮件,才过了不到一个小时,马上又反馈一封邮件,提示软件已经上架,给力!
(16). 飞流
点评:审核速度挺快的,1天吧,量比较小,支持万普积分墙。
详细:最新上传的2款软件都很快通过审核了,但是有一款很早之前的软件一直没有审核,我很无解!
(17). 百度
点评:我个人觉得比较坑爹,搞不懂它的后台管理系统,我通过抓猫提交的,审核速度比较快,没有量。
详细:感觉和百度首页的”应用“没有关系啊,搞不懂搞不懂。
(18). 联通沃商店
点评:需要签约,2-3天账户审核通过。
详细:联通,移动MM这些国内巨头,都弄的很麻烦,但是感觉东西却不怎么样
(19). 搜狐应用中心
点评:账户审核2-3天,继续等待上传软件。6. 使用抓猫
经过上面的程序后,你会觉得要是有一个统一的后台多好啊!
抓猫就是做这个的,填一份资料,一起统一发布到各大市场,可以省很多登陆后台,填写资料的时间,不过抓猫不是包括所有平台的,有一些不包括的平台还是需要手动提交。
(1). 注册各大市场的账号
这个注册的过程是少不了的。
(2). 绑定账号,如下图把账号事先都统一绑定好(我把账号都删除了,可能看不清楚),是这个意思。
(3). 一键发布
发布新应用,提交一个抓猫渠道的包或者随便提交一个吧,然后到后面分别提交各个专门渠道的包。
然后就等待上架了:确实省不少麻烦。7. 小结
不怕市场多,就怕市场拒绝。
尽量多的提交到各个市场吧,不要怕麻烦,如果是新手,我也相信本文能一定减少错误率,提高提交应用的成功率。
真心欢迎留言补充……
我们知道,解压APK后在META-INF\目录下有三个文件:
MANIFEST.MF
为了说明方便,我取.MF和.SF里的其中一条文件记录进行说明。
MANIFEST.MF里有一条是这样的
Name: assets/domob_next_off.png
SHA1-Digest: grInRNpOLXjWa5hDSdT5DS/AaLg=
那么这个SHA1-Digest计算方法为:
BYTE pdata[20];
SHA(“assets/domob_next_off.png”, pdata)
base64_str = base64encode(pdata),就会得到那个”grInRNpOLXjWa5hDSdT5DS/AaLg=”
没什么问题。
在CERT.SF里也有对应这个文件的一条:
Name: assets/domob_next_off.png
SHA1-Digest: MlJzFQET8ux3C8iVIWPRnYCt50c=
我的问题是:那么这条SHA1-Digest是如何计算得到的?
是不是这样的:
BYTE pdata[20];
SHA(“assets/domob_next_off.png”, pdata)
psign_data = rsa_sign(pdata, pivate_key),
base64_str = base64encode(psign_data),
但是看结果好像不会得到”MlJzFQET8ux3C8iVIWPRnYCt50c=”,连base64计算结果的长度都不对。
请教下,SF里的那条SHA1-Digest具体生成算法是怎么样的?
——Solutions——
apk 的签名都是有一个密钥文件的,如果你没有签过,那就是系统用一个调试版的自动签了。
——Solutions——
有没有研究过呢。自顶一下
——Solutions——
第一个你算得是对的
第二个感觉你理解错了一步
根据SHA-1算法得到文件的摘要,标准SHA-1的输出位数为160bit
SHA(“assets/domob_next_off.png”, pdata)
这个pdata应该就是摘要
然后经过BASE64编码 就会得到结果
但是第二个问题里
你直接使用psign_data = rsa_sign(pdata, pivate_key),
pivate_key应该不对,感觉会是私钥和某个固定的值混合的或者某种算法生成的
不知道你的pivate_key是什么内容
还有rsa_sign
我也不清楚具体的计算过程和方法
LZ可以讲讲rsa_sign是怎么计算的
——Solutions——
应该是将MANIFEST.MF中对应的信息使用SHA1-RSA算法,用私钥进行签名得到的。
也就是说CERT.SF文件是使用了私钥得到的,而MANIFEST.MF没有使用密钥信息,
而CERT.RSA肯定是要用公钥得到的
——Solutions——
引用 4 楼 iltgcl 的回复:
应该是将MANIFEST.MF中对应的信息使用SHA1-RSA算法,用私钥进行签名得到的。
也就是说CERT.SF文件是使用了私钥得到的,而MANIFEST.MF没有使用密钥信息,
而CERT.RSA肯定是要用公钥得到的
LZ和我想问的是
怎么计算得到的
——Solutions——
私钥 ) = 结果SHA1-RSA
“grI…..AaLg=”
“MlJzFQET8ux3C8iVIWPRnYCt50c=” ——Solutions——
引用 6 楼 iltgcl 的回复:
私钥 ) = 结果
“grI…..AaLg=”
“MlJzFQET8ux3C8iVIWPRnYCt50c=”
楼上的意思是先对文件”assets/domob_next_off.png”做SHA1,然后再用私钥对这个hash值签名.然后再base64?——Solutions——我看android调用里写的是sha1-rsa,我在想这个到底是一个什么概念的算法?是不是就是sha1做完再用私钥签名? ——Solutions——
引用 3 楼 tanwei4199 的回复:
第一个你算得是对的
第二个感觉你理解错了一步
根据SHA-1算法得到文件的摘要,标准SHA-1的输出位数为160bit
SHA(“assets/domob_next_off.png”, pdata)
这个pdata应该就是摘要
然后经过BASE64编码 就会得到结果
但是第二个问题里
你直接使用psign_data = rsa_sign(pdata, pivate_key),
pivate_key应该不对,感觉会是私钥和某个固定的值混合的或者某种算法生成的
不知道你的pivate_key是什么内容
还有rsa_sign
我也不清楚具体的计算过程和方法
LZ可以讲讲rsa_sign是怎么计算的
我的理解就是CERT.CF文件因为要校验签名的正确性,那么是这样计算的:1.先对文件做sha1,得到一个固定的hash值2.再用rsa算法,私钥进行签名,但是这样就有一个问题,用rsa算法得到的长度应该是大于hash值的,不会固定长度3.那么再做base64就会得到一个比MAINFEST.MF里长的多的base64字串,但是看结果CERT.CF里的每个base64结果都一样长且和MAINFEST.MF一样,我就感觉比较奇怪,这个CERT.CF里每个值的由来。比较CF和MF两个文件里的毎对base64值,长度都一样。 ——Solutions——
引用 9 楼 china_helper 的回复:
Quote: 引用 3 楼 tanwei4199 的回复:
第一个你算得是对的
第二个感觉你理解错了一步
根据SHA-1算法得到文件的摘要,标准SHA-1的输出位数为160bit
SHA(“assets/domob_next_off.png”, pdata)
这个pdata应该就是摘要
然后经过BASE64编码 就会得到结果
但是第二个问题里
你直接使用psign_data = rsa_sign(pdata, pivate_key),
pivate_key应该不对,感觉会是私钥和某个固定的值混合的或者某种算法生成的
不知道你的pivate_key是什么内容
还有rsa_sign
我也不清楚具体的计算过程和方法
LZ可以讲讲rsa_sign是怎么计算的
我的理解就是CERT.CF文件因为要校验签名的正确性,那么是这样计算的:
1.先对文件做sha1,得到一个固定的hash值
2.再用rsa算法,私钥进行签名,但是这样就有一个问题,
用rsa算法得到的长度应该是大于hash值的,不会固定长度
3.那么再做base64就会得到一个比MAINFEST.MF里长的多的base64字串,但是看结果CERT.CF里的每个base64结果都一样长且和MAINFEST.MF一样,我就感觉比较奇怪,这个CERT.CF里每个值的由来。
比较CF和MF两个文件里的毎对base64值,长度都一样。
我查了下文档
得到MAINFEST.MF里面的内容 然后通过密钥加密MAINFEST.MF
得到CERT.CF
解析CERT.CF
与MAINFEST.MF 对比
——Solutions——
本人对JAVA不太懂,开始想是不是能通过PHP技术来解决这个问题。但是通过查找各方面的 资料,没有找到好的办法。
最后转而去先了解了一下JAVA对包签名原理,再通过JAVA方面去找答案,最终是解决了这个问题。可是这样解决的方法,并不是 我期待的。我很希望会有更加简洁的方法实现,如果有更好解决的方案的朋友,可以留言给我。希望多交流。
下面就讲一下取比对APK签名一致的步骤,总的步骤先归纳如下几点,然后我分别做解释:
1.在服务器上安装JDK,使用keytool命令生效。
2.分别到取到二个APK包的证书指纹。
3.通过指纹信息,对比是否相等,判断是否为同一软件。
现在按上面给出的思路,来执行操作就可以。我们接着往下走:
第一步:在CentOS服务器下安装JDK,让keytool命令生效可以使用。
a.下载适合贵公司服务器的JDK版本。
下载址址:
我测试的时候,下载的是:jdk-6u29-linux-x64.bin 。
[root@web-1 home]# wget /otn-pub/java/jdk/6u29-b11/jdk-6u29-linux-x64.bin
b.安装并配置JDK.
[root@web-1 home]# ./jdk-6u29-linux-x64.bin
[root@web-1 home]# mv jdk1.6*
/usr/local/java
[root@web-1 home]# cat && /etc/profile
########################################
JAVA_HOME=/usr/local/java
JRE_HOME=\$JAVA_HOME/jre
CLASSPATH=:\$JAVA_HOME/lib:\$JRE_HOME/lib
PATH=\$JAVA_HOME/bin:\$JRE_HOME/bin:\$PATH
export JAVA_HOME JRE_HOME CLASSPATH PATH
########################################
c.测试JAVA环境是否正常。
[root@web-1 home]# java -version
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02, mixed mode)
如果有类似如上输出,证明你的配置成功,恭喜!
注:Windows服务器的安装,我没有做测试,网上教学一堆,所以是Windows服务器的同学可以找找怎么安装JDK。
第二步:通过组合命令取到APK包CERT.RSA证书指纹(MD5或SHA1值)。
注:CERT.RSA文件中保存了公钥、所采用的加密算法等信息。
a.取到第一个包名的证书指纹。
unzip -p mumayidianzishichang_Mumayi_Market_V1.4_mumayi_91db5.apk META-INF/CERT.RSA | keytool -printcert | grep MD5
unzip -p mumayidianzishichang_Mumayi_Market_V1.4_mumayi_91db5.apk META-INF/CERT.RSA | keytool -printcert | grep SHA1
[root@web-1 1]# unzip -p mumayidianzishichang_Mumayi_Market_V1.4_mumayi_91db5.apk META-INF/CERT.RSA | keytool -printcert | grep MD5
19:2A:5C:11:3E:72:A0:A1:A1:10:A3:BE:C3:9C:D5:32
[root@web-1 1]# unzip -p mumayidianzishichang_Mumayi_Market_V1.4_mumayi_91db5.apk META-INF/CERT.RSA | keytool -printcert | grep SHA1
SHA1: 91:83:AF:08:B5:00:88:85:E6:4C:E9:41:4E:3B:06:EC:51:E8:F8:83
Signature algorithm name: SHA1withRSA
a.取到第二个包名的证书指纹。
unzip -p mumayidianzishichang_Mumayi_Market_V1.5.9_mumayi_9454a.apk META-INF/CERT.RSA | keytool -printcert | grep MD5
unzip -p mumayidianzishichang_Mumayi_Market_V1.5.9_mumayi_9454a.apk META-INF/CERT.RSA | keytool -printcert | grep SHA1
[root@web-1 1]# unzip -p mumayidianzishichang_Mumayi_Market_V1.5.9_mumayi_9454a.apk META-INF/CERT.RSA | keytool -printcert | grep MD5
19:2A:5C:11:3E:72:A0:A1:A1:10:A3:BE:C3:9C:D5:32
[root@web-1 1]# unzip -p mumayidianzishichang_Mumayi_Market_V1.5.9_mumayi_9454a.apk META-INF/CERT.RSA | keytool -printcert | grep SHA1
SHA1: 91:83:AF:08:B5:00:88:85:E6:4C:E9:41:4E:3B:06:EC:51:E8:F8:83
Signature algorithm name: SHA1withRSA
注意红色框中的MD5与SHA1值,显然后上面二个APK包的版本是一样的,但是他们二个的MD5与SHA1值是相等的。能过这个值,我们就可以
判断出来二个APK中的CERT.RSA文件中保存了公钥、所采用的加密算法等信息是一样的。间接地可以得到,签名信息一致。
最后一步:
通过上面取到的正版的MD5或SHA1值存到数据库中,用于比对新上传的APK软件。如果相等证明APK签名一致,反之说明些APK软件被“污染”。
通过上面的说明,估计大家明白了这其中的原理。只要我们能拿到CERT.RSA证书指纹(MD5或SHA1值)。就可以做APK签名比对的功能了。
最后说一下这种实现方式不足的地下存在二点:
1.在PHP程序方面,需要开启exec,shell_exec等shell命令函数,产生不安全隐患。
2.需要安装JDK,间接地加重了服务器管理与维护的成本。
参考文章与资料:
1.《》这文章写的相当详细,非常感谢此文章作者。
This entry was posted in
and tagged
by . Bookmark the .
为android构建一个插件
要创建一个android插件,首先要有
并熟悉使用ndk构建共享库的方法。
如果用C++来实现库,必须声明成用C语言的链接方式,以避免问题。
extern "C" { float FooPluginFunction (); }
通过C#脚本使用插件
构建了共享库后,必须把共享库复制到unity3d工程中的Assets-&Plugins-&Android目录下。(没有该目录的话,自己依次创建。)
当你在unity3d中在C#脚本中定义如下的函数时,unity3d就能通过名称找到共享库
[DllImport ("PluginName")] private static extern float FooPluginFunction ();
注意PluginName不要包含共享库文件名中的“lib”前缀和“.so”后缀。建议所有的native代码方法都用C#代码封装一层,并在C#代码中检查变量,以保证只有app运行在正确的设备上时,才去调用native方法。当在Editor环境下运行时,可以在C#代码中返回空值。
当然也可以用的方法,来控制与平台相关的代码的编译。
对于要部署到多个平台的项目,项目工程中必须包含各个平台所需要的插件(例如:libPlugin.so用于android平台,Plugin.bundle用于mac平台,Plugin.dll用于windows平台)。unity3d会自动为目标平台选择正确的插件。
使用java插件
android插件机制同样允许使用java来与android系统进行交互。
为android构建一个java插件
有好几种方法来构建java插件,最终结果都是生成包含.class文件的.jar包。一种方法是下载 ,在命令行下用javac命令编译,用jar命令打包成jar文件;另一种方法是 +。
在native代码中使用java插件
构建好了java插件后,将java插件(.jar)复制到 unity3d工程中的Assets-&Plugins-&Android文件夹下面,unity3d会将你的.class文件和其余的java代码打包,并通过来访问这些代码。JNI既可以用于java代码调用native代码,也可用于native代码与java(java虚拟机)的交互。
要找到你的java代码,必须要能访问到java虚拟机。幸运的是,可以通过在c/c++代码中添加如下函数来很容易的实现这种访问:
jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* jni_env = 0; vm-&AttachCurrentThread(&jni_env, 0); }
这个是从c/c++调用java所必需的。JNI超越了本文档的范畴,不做详细解释。通常情况下,先找到类的定义,然后解析类的构造方法(&init&)并创建类的实例,如下面例子所示:
jobject createJavaObject(JNIEnv* jni_env) { jclass cls_JavaClass = jni_env-&FindClass("com/your/java/Class");
// 找到类定义 jmethodID mid_JavaClass = jni_env-&GetMethodID (cls_JavaClass, "&init&", "()V");
// 找到构造方法 jobject obj_JavaClass = jni_env-&NewObject(cls_JavaClass, mid_JavaClass);
// 创建对象实例 return jni_env-&NewGlobalRef(obj_JavaClass);
// return object with a global reference }
通过帮助类来使用java插件
使用AndroidJNIHelper 和AndroidJNI会减轻些使用原始JNI的痛苦。
AndroidJNIHelper 和AndroidJNI自动完成了很多任务(指找到类定义,构造方法等),并且使用缓存使调用java速度更快。AndroidJavaObject和AndroidJavaClass基于AndroidJNIHelper 和AndroidJNI创建,但在处理自动完成部分也有很多自己的逻辑,这些类也有静态的版本,用来访问java类的静态成员。
你可以选择任意你喜欢的方式来替代这种原始JNI的做法,可以通过 AndroidJNI类,也可以通过AndroidJNIHelper和AndroidJNI, 最后也可以使用 AndroidJavaObject/AndroidJavaClass,这样会有最大程度的自动完成和最大的便利性。
是对那些c代码可用的JNI调用的封装,该类中的所有方法都是静态的并且一一对应到JNI。
通过public方法提供了一些不常用的辅助功能,在某些特殊情况下会比较有用处。
在java端,和的实例分别一一对应于 java.lang.Object和java.lang.Class (或它的子类)的实例。它们提供了3种与java端交互的方法:
Call分为两类,调用void方法和调用非void返回类型的方法,会使用一个泛型类型来表示这些非void返回类型的方法的返回类型;Get和Set也经常带一个泛型类型用以表示域的类型。
//注释表示是使用原始JNI方法必须做的工作 AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string"); // jni.FindClass("java.lang.String"); // jni.GetMethodID(classID, "&init&", "(Ljava/lang/S)V"); // jni.NewStringUTF("some_string"); // jni.NewObject(classID, methodID, javaString); int hash = jo.Call&int&("hashCode"); // jni.GetMethodID(classID, "hashCode", "()I"); // jni.CallIntMethod(objectID, methodID);
这个例子中,我们创建了一个 的实例,并用我们自定义的一个字符串初始化它,最后我们得到该字符串的哈希值。
AndroidJavaObject的构造方法至少需要一个参数—-你想要实例化的类的名称。类名之后的参数会被对象的构造函数所使用,如上例种的字符串“some_string”,随后的对hashCode方法的Call会返回一个int型值,这也是为什么我们会传一个泛型参数给Call方法。
注意:不能使用点.来初始化一个嵌套类型,内部类必须使用$分隔符,在斜线/或点.分隔的类名中都可以使用。所以当类LayoutParams嵌套在ViewGroup类中时,像android.view.ViewGroup$LayoutParams或者android/view/ViewGroup$LayoutParams,这两种方式都是可行的。
上面有个插件的例子是说获取当前程序的缓存目录的,下面这个例子直接用c#代码做同样的事情,而不需要任何插件:
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); // jni.FindClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo = jc.GetStatic&AndroidJavaObject&("currentActivity"); // jni.GetStaticFieldID(classID, "Ljava/lang/O"); // jni.GetStaticObjectField(classID, fieldID); // jni.FindClass("java.lang.Object"); Debug.Log(jo.Call&AndroidJavaObject&("getCacheDir").Call&string&("getCanonicalPath")); // jni.GetMethodID(classID, "getCacheDir", "()Ljava/io/F"); // or any baseclass thereof! // jni.CallObjectMethod(objectID, methodID); // jni.FindClass("java.io.File"); // jni.GetMethodID(classID, "getCanonicalPath", "()Ljava/lang/S"); // jni.CallObjectMethod(objectID, methodID); // jni.GetStringUTFChars(javaString);
这个例子中,我们没有首先使用AndroidJavaObject,而是AndroidJavaClass ,因为我们想获取类com.unity3d.player.UnityPlayer的一个静态成员,而不是去创建一个新的对象(Android UnityPlayer会自动创建一个实例)。我们访问其静态域”currentActivity” ,这个时候我们用的是AndroidJavaObject作为泛型参数,这是因为实际类型()是类的子类,任意都必须作为AndroidJavaObject来访问。有一个例外就是字符串,字符串可以直接访问,尽管它在java中并不是基本类型。
之后就是调用的Activity的getCacheDir()得到缓存目录的文件对象,再调用方法获取缓存目录路径的字符串表示。
当然,现在已经不需要通过这种方式来获取缓存目录了,因为unity3d提供了接口用以访问程序的缓存目录和数据目录,也就是 and 。
最后,是一个通过UnitySendMessage方法从java代码向脚本代码传递数据的小窍门。
using UnityE public class NewBehaviourScript : MonoBehaviour { void Start () { JNIHelper.debug = using (JavaClass jc = new JavaClass("com.unity3d.player.UnityPlayer")) { jc.CallStatic("UnitySendMessage", "Main Camera", "JavaMessage", "whoowhoo"); } } void JavaMessage(string message) { Debug.Log("message from java: " + message); } }
类com.unity3d.player.UnityPlayer现在有一个静态方法UnitySendMessage,与iOS中native端的一样,可用来在java中向脚本传递数据。
这里我们直接从脚本中调用的,但它确实是在java端发送的消息,它会调回到unity3d的native代码,传递消息到名为”Main Camera“的游戏对象上去,该对象上绑定的某个脚本中包含有名为”JavaMessage”的方法。
在unity3d中使用java插件的最佳实践
这一节主要针对那些没有足够jni,java和android经验的人。假设我们在unity3d中使用AndroidJavaObject/AndroidJavaClass来与java交互。
首先就是要注意对AndroidJavaObject/AndroidJavaClass的任何操作都是很费时的(是通过JNI来进行的)。因此为了代码性能和代码清晰性,我们强烈建议托管代码与native/java代码间的转换次数保持在最小数量。
你可以定义一个java方法完成所有的事情,然后我们通过AndroidJavaObject/AndroidJavaClass来与这个方法通信和获取结果,我们的JNI帮助类会尽可能多的缓存数据已提高性能。
//第一次像这样调用java函数 AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string"); // 有点费时 int hash = jo.Call&int&("hashCode"); //第一次 - 费时 int hash = jo.Call&int&("hashCode"); // 第二次 - 不那么费时, 因为我们已经知道了这个java方法,可以直接调用它。
在使用过后,Mono垃圾回收器会释放所有创建的AndroidJavaObject和AndroidJavaClass实例,但我们还是建议把它们放到using(){}块中,以保证它们能被尽快的清除掉。除此之外,你无法保证它们会被销毁掉。如果你设置了AndroidJNIHelper.debug为true,你会在log输出中看到垃圾回收器的活动记录。&
//获取系统语言的安全方法 void Start () { using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale")) { using(AndroidJavaObject locale = cls.CallStatic&AndroidJavaObject&("getDefault")) { Debug.Log("current lang = " + locale.Call&string&("getDisplayLanguage")); } } }
也可以直接调用.Dispose()方法确保没有java对象残留,c#对象会存活长一点,最终还是会被mono的垃圾回收器回收。
继承UnityPlayerActivity java代码
在Unity Android上,我们可以继承标准的UnityPlayerActivity类(android上Unity Player的主要java类,类似于Unity iOS上的AppController.mm)。
应用程序可以覆写android系统与Unity Android之间的任意交互方法,只要新建一个继承UnityPlayerActivity就可以实现。(在mac系统上,UnityPlayerActivity.java在/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player目录下;在windows系统中,它通常在C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player目录下)
首先定位Unity Android的classes.jar文件,可以在Unity3d的安装目录(windows下通常是C:\Program Files\Unity\Editor\Data,mac下是/Applications/Unity)下的子文件夹PlaybackEngines/AndroidPlayer/bin中找到,将它添加到你编译activity的classpath中。最终编译出来的.class文件,需要打包成.jar文件,放到工程中的Assets-&Plugins-&Android目录下。因为android中manifest文件指明了启动哪个Activity,因此我们也需要重新写一个文件,也需要将它放到Assets-&Plugins-&Android目录下。
继承UnityPlayerActivity的一个例子,OverrideExample.java:
pany. import com.unity3d.player.UnityPlayerA import android.os.B import android.util.L public class OverrideExample extends UnityPlayerActivity { protected void onCreate(Bundle savedInstanceState) { // call UnityPlayerActivity.onCreate() super.onCreate(savedInstanceState); // print debug message to logcat Log.d("OverrideActivity", "onCreate called!"); } public void onBackPressed() { // instead of calling UnityPlayerActivity.onBackPressed() we just ignore the back button event // super.onBackPressed(); } }
相关的AndroidManifest.xml文件如下:&
&?xml version="1.0" encoding="utf-8"?& &manifest xmlns:android="/apk/res/android" package="pany.product"& &application android:icon="@drawable/app_icon" android:label="@string/app_name"& &activity android:name=".OverrideExample" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"& &intent-filter& &action android:name="android.intent.action.MAIN" /& &category android:name="android.intent.category.LAUNCHER" /& &/intent-filter& &/activity& &/application& &/manifest&
UnityPlayerNativeActivity
同样我们可以创建UnityPlayerNativeActivity的子类,这与创建UnityPlayerActivity的子类具有相同的效果,但是会有较小的输入延迟。但是,需要明白的是,NativeActivity是在Gingerbread中引入的(即android 2.3),老的android版本没有这个特性,因为在NativeActivity中,触摸事件都是在native代码中处理的,java视图正常情况下是无法获取这些事件的,不过在unity3d中,有允许将事件传到DalvikVM的转发机制,要应用这个转发机制,必须修改manifest文件如下:
&?xml version="1.0" encoding="utf-8"?& &manifest xmlns:android="/apk/res/android" package="pany.product"& &application android:icon="@drawable/app_icon" android:label="@string/app_name"& &activity android:name=".OverrideExampleNative" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"& &meta-data android:name="android.app.lib_name" android:value="unity" /& &meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" /& &intent-filter& &action android:name="android.intent.action.MAIN" /& &category android:name="android.intent.category.LAUNCHER" /& &/intent-filter& &/activity& &/application& &/manifest&
要注意activity元素中的.OverrideExampleNative属性,还有两条meta-data元素,第一条meta-data元素指明使用unity3d库libunity.so,第二条meta-data元素使事件能传递到你创建的UnityPlayerNativeActivity子类中。
native插件例子
有一个简单的使用native插件的例子。
这个例子演示了如果从unity3d android程序中来调用c代码,包中包含了一个通过native插件计算出来的两个数之和的场景,要注意,你必须用来编译这个插件。
java插件例子
有一个简单的使用java代码的例子。
这个例子演示了怎么用java代码与android系统进行交互,以及如何用c++来将c#和java沟通起来,包中的场景显示了一个按钮,点击该按钮,会显示出程序在android系统中的缓存目录路径。需要JDK和 来编译这个插件。
有一个相似的例子,但是是基于预先编译好的JNI库,来封装native代码,供c#调用。
android 一般除了使用jarsigner签名 还有使用signapk 后者位于android源码 前者位于jdk中。两者使用的文件格式不同前者使用JKS 后者使用公钥+私钥 是分开的
第一步 先v把keystore文件转换为pkcs12格式
-importkeystore -srckeystore debug.keystore
-destkeystore tmp.p12 -srcstoretype JKS
-deststoretype PKCS12
第二步 将PKCS12 dump成pem 这样就可以按照文本形式查看了
pkcs12 -in tmp.p12 -nodes -out tmp.rsa.pem
接下来打开文件intermediate.rsa.pem 看到 PRIVATE KEY 还有CERT PS:private 那边可能有RSA KEY 这个不用管Bag Attributes
friendlyName: androiddebugkey
localKeyID: 54 69 6D 65 20 31 33 38 38 39 37 38 34 32 36 38 36 39 Key Attributes: &No Attributes&—–BEGIN PRIVATE KEY—–…—–END PRIVATE KEY—–Bag Attributes
friendlyName: androiddebugkey
localKeyID: 54 69 6D 65 20 31 33 38 38 39 37 38 34 32 36 38 36 39 subject=/C=US/O=Android/CN=Android Debugissuer=/C=US/O=Android/CN=Android Debug—–BEGIN CERTIFICATE—–…—–END CERTIFICATE—–复制“BEGIN CERTIFICATE”
“END CERTIFICATE” 到(新建个文件) cert.x509.pem[ pem里面内容(下的一样):—–BEGIN CERTIFICATE—–。。。。—–END CERTIFICATE—–]复制 “BEGIN RSA PRIVATE KEY”
“END RSA PRIVATE KEY” 到(同上) private.rsa.pem第三 生成pk8格式的私钥
openssl pkcs8 -topk8 -outform DER -in
private.rsa.pem -inform PEM -out private.pk8 -nocrypt
完毕 收集文件 cert.x509.pem private.pk8 其余的中间文件删除即可
PS:-nocrypt 这个参数设定key加密 如果设置了这个参数 下面签名 只要证书+key 不需要密码了 如果加密 应该 openssl pkcs8 -topk8 -outform DER -in private.rsa.pem -inform PEM -out private.pk8 接下来输入密码
用法 java -jar signapk.jar cert.x509.pem private.pk8 unsigned.apk signed.apk

我要回帖

更多关于 暗影精灵2最大内存 的文章

 

随机推荐