子鸿技术博客


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索
close

斗米客户端的架构思想

发表于 2017-07-27   |   分类于 架构设计   |   阅读次数

背景

随着移动互联网产业的兴起,各式App层出不穷,技术方案多种多样。同样,我们也面临了各式各样的问题,比如产品如何开发能够更快速迭代上线,如何使运营推广更灵活,如何降低研发成本,提高研发效率和质量。随意产品开发的深入,我们越来越迫切寻求探索这些问题的解决方案。

经过这些年在APP端、浏览器内核、H5、server端研发经验的积累,2015年我在斗米的客户端产品上首次提出了以URD驱动webox的客户端平台化架构思想,并经过两年时间多个产品的探索实践,我认为该APP端的架构思想可正式对外分享。由于篇幅原因,今天我只从架构思想和原理上进行分享,而不对实现分享,希望能够给正在探索同样问题的朋友们带来一些思考和灵感。

目前行业内APP可分为三大类:Web App、Native App、Hybrid App。以下我将围绕Hybrid APP的架构思想展开分享,至于为什么使用Hybrid App来分享,后文会阐述这三种App的优缺点。当然,该架构思想也同样适合纯 Native App。

为了更好理解本文,欢迎下载斗米兼职客户端体验,斗米客户端的H5化已达到90%以上。

架构思想总述

先简单说明下URD和Webox概念

  • URD是统一资源调度器,英文名Uniform Resource Dispatcher。它是一个用于跨平台、跨端进行资源调度的字符串,允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。
  • webox用于承载内容页面统称为框(webox),全称Web Box。webox包含Blockbox和Browser

解决的问题

1、跨平台、架构一致性

现阶段主流的移动OS当属Android和iOS,大多数产品都会覆盖这两个平台。因Android和iOS的平台机制原因,造成在这两个平台的技术架构上产生了分歧。逐渐地,这两个平台的APP就相对独立,实现方案的也有了较大的差异化,系统性技术方案不好落地,沟通、维护成本逐渐变大,这也是架构师们经常头疼的一件事。

有没有遇到这样的场景:

  • 人力资源不足,我们希望在一个平台上实现,然后可以在其他平台上运行
  • 新出了一个平台,比如微信小程序,业务需要重新开发,如果业务能够复用多好
  • 如果公司有多个产品,我们需要基础服务复用,架构一致,降低沟通成本
  • iOS和Android在产品的技术实现上不一致,这时候,服务端需要做这两个平台的兼容。
  • 有时候,对外运营推广的接口不统一,市场就需要对这两个平台单独做推广

因此,遇到这些问题的抓狂,我们认识到跨平台、架构一致性的解决方案,对我们来说是何等的重要。

2、产品迭代快,快速发版

我们都知道APP发版不是一件容易的事,需要把包传给各个渠道。若是紧急出现重大bug,这时候我们就需要重新打好所有的渠道包,重新走发版流程,这对各个团队来说是件痛苦的事。

产品能够快速发版,甚至只需要热更新即可。这是产品快速试错,打击竞品的一把利剑。
在斗米的各客户端中,在APP不需要发版的前提下,可以使用DEK发版。DEK是一种用于热更新的包,可快速上线,并且跨平台(iOS、Andoid共用),就像web上线那么简单灵活。
APP的发版节奏一般是三四周左右,而DEK发版,如果只是fix bug的话,一两天即可完成发版,若是需求发版一周以内即可完成,

3、运营推广更灵活

URD是这套架构方案的核心驱动力,更是运营推广的重要工具。

  • 场景1:端内运营
    1、一般运营活动的落地页是web页面实现,想从活动落地面点击跳转到APP的某产品详情页(或者其他任何APP的页面),在有了URD机制后,运营推广部门不需要给客户端团队提需求实现,只需要使用URD即可跳转到APP的任何页面。
    2、当web嵌入到客户端内,当有发现有涉及到我们客户端已实现的页面(如详情页),会自动302跳转到APP页面,提高了用户体验。

    当然我们使用cookie的机制,端内与web的登录态也会互相同步

  • 场景2:端外运营
    当我们和第三方合作业务时,在第三方app或者第三方web站,我们可以提供URD给对方,URD具备调起app并且跳转到APP某页面的能力

4、解耦、扩展能力

URD与webox的相结合,使得app的解耦和扩展能力极强。URD是驱动力,能够做到跨平台页面调度,比如H5调度webox,Native调度webox,服务端调度webox,端外调度webox,webox内的内容也可跳到端外的能力;而webox是承载页面,承载内容的容器,内容使用DEK部署,DEK可热更新。整套机制跨平台,灵活度高,解耦和扩展能力强。

5、降低成本

研发成本的降低,在这套架构上体现得较为明显。业务开发,以JS言语为主,Native主要负责框架、性能相关的支持。而JS是一门跨平台,而且扩展性良好的语言,在Hybrid App的开发人力相对于纯Native App的开发人力上可缩减一半

APP分类

目前APP大致分成三类

Web App

定义: 将所有功能都放在Web上展现,运行基于本地浏览器。在此将给Web简单的套一层App外壳的应用也归入Web App。完全采用HTML/CSS/JS编写,专为触摸操作进行了优化。目前iOS已禁止简单的套壳App上架。

优点: 开发速度快,跨平台,成本低,实时迭代用户无需更新

缺点: 网络速度要求高、服务器压力大,系统级别API调用难度大,用户体验差、用户留存度低

Native App

定义: Native App是基于手机本地操作系统并使用原生语言编写的 。因为位于平台层上方,向下访问和兼容的能力会比较好一些,可以支持在线或离线访问,消息推送或本地资源访问,摄像拨号功能的调 取。但是由于设备碎片化,App的开发成本要高很多,维持多个版本的更新升级比较麻烦,用户的安装门槛也比较高。

优点: 用户体验佳、交互风格与系统吻合,节省流量,可访问本地资源,速度快,用户留存度高

缺点:成本高,版本迭代慢,需要过审

Hybrid App

定义: 介于Web App与Native App的一种折中方案,底层(框架)部分由iOS/Android开发人员处理,上层(内容展现)部分由Web前端人员处理,用户界面操作逻辑及部分静态资源驻留本地,使得Web App可以对操作迅速反应并在很大程度上实现离线访问。
Hybrid App分为四种:单View混合型、多View混合型、web主体型、多主体共存型(灵活型),点这里看百科

多主体共存型Hybrid App能够实现趋近于原生App的体验。
以下对多主体共存型Hybrid APP说明优缺点。

优点:具有跨平台、用户体验好、扩展性好、灵活性强、易维护、规范化、具有Debug环境、彻底解决跨域问题。

缺点:多一端的团队参与就多一些沟通成本,如接口的沟通,有js与Native的接口,有js与server的接口

架构解析

说到斗米客户端的架构,不得不简单介绍一下kerkee。
斗米客户端基础框架使用的是kerkee框架(http://www.kerkee.com),kerkee是一个多主体共存型Hybrid框架,具有跨平台、用户体验好、性能高、扩展性好、灵活性强、易维护、规范化、集成云服务、具有Debug环境、彻底解决跨域问题。

整体结构图

整体结构分成以下几部分,斗米客户端会把这些基础能力封装到DoumiFramework中,便于其他项目的使用。

  • Application层:主要有URD架构和Webox容器架构,以及一些业务模块,Webox容器在架构思想形成的前两个版本叫作多框一Browser,是不是很通俗易懂,当时还未对容器构建模型。
    “多框一Browser”是用来加载本地页面和web页面的容器。后来发现“多框一browser”过于随意性,对框的定义是根据功能来区别,比如加载首页就叫首页框,加载详情页就叫详情页框,加载列表页就叫列表框等等,当页面的种类越来越多的情况下,框也就越来越多,就造成了泛滥,没有统一的类型,沟通上的成本也越来越大。后来也对框进行建模,建立规范,才有了今天的Webox,后面会介绍。
    URD也是这套架构的核心驱动力,URD是基于RFC 3986规范而制定的一套跨平台规范。URI相信大家都能理解和使用,但URD不是URI,只是在调用和使用层面和URI的用法一样。

  • API层:这一层很重要,它是JS与Native交互的API接口。这层的API可以重写kerkee中功能。比如你看kerkee中实现的XMLHttpRequest(简称XHR)实现的不好,那你就可以重写XHR接口,完全取代kerkee中的XHR模块。这层的接口可以使用静态类,也可以使用对象,具体用法可以查看kerkee的使用。

  • kerkee Framework:是我早年实现的一套Hybrid App框架,目前相对稳定。这个lib就不多说了,基本这个lib之上,还有个kerkee plus,它的作用封装了热部署,以及一些功能接口。具体细节可以去网上看 http://www.kerkee.com
  • Intelligent Data Engine:这是数据层,把所有的数据逻辑圈在这层内,它定义了数据请求来源,数据运行逻辑,形成数据流。
    举个例子,它能够提供给Application层,不管数据是从缓存读取还是从离线数据库读取或者是从server请求。而Application层不需要关心数据来源。
    一般来说,对于APP开发,业务稳定下来后,数据层一般变化得较少,变化较多的是用户体验层(Application层),有了数据层后,app的结构就清晰起来。

安全策略

我们在数据的安全方面下了很大功夫。
AccessToken机制
先介绍一下名词:
DEK加密算法:自研发的加密算法,稳定性高,安全性较好,现在整个斗米的api接口基本都基于此进行加密
DeviceToken:设备唯一标识,由我们自研发的一套设备唯一标识
AccessToken:访问接口所需要和token,它由client发起,动态改变,每次发起请求都会生成不一样的AccessToken,就和银行的eToken类似的原理,就是以下图片这东西

AccessToken包含了DeviceToken等信息,经过DEK加密算法处理后,再进行上报。如果请求的数据中没有AccessToken或AccessToken校验不通过,则不会下发数据。

附加:
我们对所有的请求都使用了https,为了安全,我们损失了一些请求接口的性能作为代价。

Webox

用于承载内容页面统称为框(webox),全称Web Box。Webox包含Blockbox和Browser。
根据承载的区块上来区分:“Blockbox”所承载的内容可以是Native组件,也可以是H5组件(还可以是H5 Page),而Browser所承载的内容只能是H5 Page
根据区块的路径来区分:“Blockbox”不仅支持相对路径Path,也支持绝对路径Full Path和标准URL;Browser只支持URL。

举例:

Blockbox:通用框(common blockbox)、首页框、详情框、列表框、登录框等
Browser:用来承载Web页面的框

URD

什么是URD

字面上的URD
URD是统一资源调度器,英文名Uniform Resource Dispatcher。它是一个用于跨平台、跨端进行资源调度的字符串,允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。
URD协议沿用URI规范(RFC 3986规范),文档地址:http://www.ietf.org/rfc/rfc3986.txt

URD格式
scheme://action/path-encoding?query#fragment

URD和URI的区别
URI是以一种抽象的,高层次概念定义统一资源标识;
URD所定义的协议是在URI之上,URD是具体资源调度的方式,可用资源的分发调度。URD不仅是一种URI的表现形式,它还可以嵌套URL和其他URI。

架构上的URD
URD是一套客户端技术架构,也是一门技术哲学,是客户端的驱动力,是webbox内容的身份标识。
具备了跨平台调度页面、多层嵌套、数据回传、单向页面依赖调度、URD302等特性

重要特性

跨平台调度页面:H5可以调度webox,Native调度webox,服务端调度webox,端外调度webox,webox内的内容也可跳到端外的能力

多层嵌套:URD页面可以调度另一个URD页面

数据回传:通过URD可以传递数据(包括透传数据)和回传数据

单页面依赖调度:
使用例子来说明,比如从H5某个页面发起URD去调度用户钱包页面,而钱包页面又依赖于登录,对于调起方来说不需要知道进入钱包是否需要登录或是否已登录,URD会自动调起登录进行登录,然后再自动去钱包页面。

支持302跳转:
URD302跳转与http的302类似,发起一个URD302以后,会销毁发起方的页面。
场景:有时候我们客户端嵌入第三方web页,但第三方web页又没有使用URD调用客户端中的页面。这时在web页中使用URD302,browser会自动识别client中已有的webox页面并自动跳转到native页面,当用户点击后退时,也会退回上一层web面,这样能够提高用户体验。
举个例子:AWeb页面要去BWeb页面,BWeb页面在client中有对应的BClient页面。AWeb页面跳转打开BWeb页面,在BWeb页面中会发起URD302,这时URD就会跳转到BClient页面,同时销毁BWeb页面,当用户需要后退时,只会回到AWeb页面

URD导图

为什么要用URD

URD是一个跨平台的规范,依靠scheme,它可以调起iOS App和Android App,不仅如此,跨平台页面调度变得更加灵活、跨平台数据传递也带来很多便利。URD在整个架构中,页面调度解耦,灵活,扩展性好。在运营和推广方面,也变得更加灵活。

Webox的调起流程
至于URD交互流程较为复杂,也不是本篇文章的篇幅所能讲述的,在这里我分享下Webox调起流程,请看图。

###DEK升级###
这一节也是比较复杂,我分享实现的基本原理。在使用上没这么复杂,每个webapp都有一个ID,ID为0时,全量更新(包含所有webapp),ID非0,增量更新,针对webapp的更新由webapp主入口的manifest决定如何更新即可。

使用

客户端会向server请求所需要更新的webapp列表,server返回所需更新的webapp数组

例如 [{id=0, manifest="webapp入口manifest"}]

client根据id判断是全量更新还是只更新某webapp,此时的全量指的是包含所有的webapp

原理

DEK更新机制(采用manifest文件的格式)遵循html5离线存储规范. H5中只是对里面的注释功能进行了扩展,native对Html5离线存储规范的重新实现及扩展。

格式:# [名称]: [值] 即 井号+空格+名称+冒号+空格+值

  • 在H5的模版化架构设计中,每个模块都形成独立的webapp(框架也是webapp,每个模块运行在框架内),每个webapp可独立更新(以dek文件体现)
  • 每个webapp又可拆分为多个DEK(当然一个DEK也可以),便于增量更新
  • 每个webapp都有一个入口manifest,每一个dek会对应一个manifest
  • 可实现全量更新(所有的webapp)和增量更新(单个webapp)
  • 文件级更新:若只更新webapp,则cache字段或network字段决定dek包中的文件更新方式,若cache字段为空,则说明该webapp全量更新(此时的全量是,某个webapp的全量)

Manifest文件格式

CACHE MANIFEST

# Version: 1.0.0.1
# RequiredVersion: 1.0.0
# List: ./others/cache.manifest, is/xx.manifest, ../../xx/xx.manifest
# Dek: xx.dek

CACHE:
images/1.0/bg.jpg
musics/1.3/bg.mp3
css/xx.1.2.min.css
xx.1.1.min.js

NETWORK:
*

格式说明

构建体系

看图!这是个webapp构建部署的结构图。

总结

以URD驱动Webox的客户端平台化架构思想在实际的实践中,较为灵活,可操作性强,对团队具有指导性作用。

文档规范

发表于 2016-11-15   |   分类于 规范   |   阅读次数

概要

目的

为了规范文档管理工作,提高团队协作效率,输出高质量的文档,特制定本规范。本规范文档一经确认, 所有开发人员必须按本文档规范进行执行. 本规范如有不对或者不合适的地方请及时提出, 经讨论决定后方可更改.

范围

本规范适用于项目文档、API接口文档、使用说明文档、架构文档等

文档基本准则

符合Markdown标准, 结构要有层次感,逻辑清晰简洁

文档管理

使用git仓库对markdown文档进行管理
有两种方式:

  1. 跟随代码仓库一起管理,例如在项目的根目录下有一个docs目录里面放文档
  2. 单独创建 XX_doc的仓库来管理

至于选择哪种方式,可以择优而定。若是多个项目团队共同协作文档,建议选择第二种方式。

最终文档会使用gitbook在文档服务器进行展现,由文档最高管理员统一申请域名并部署

规范

项目文档

在项目(代码仓库)的根目录下必须有一个”docs”目录,该目录下主要是用来存放相关文档

文档目录结构

文档仓库根目录必须包含以下几个文件
book.json 可选 gitbook的一些配置,比如可以指定展现的模版主题
README.md 必须 写一些相关介绍
usage.md 必须 写该项目或框架的使用说明
SUMMARY.md 必须 主要是book目录,每添加一个文档都需要在这个文件中添加目录

book.json的举例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"title" : "斗米客户端研发部文档",
"language" : "zh-hans",
"plugins": ["theme-comscore",
"-sharing",
"-search",
"-lunr",
"search-plus",
"splitter",
"expandable-chapters-small",
"-highlight",
"prism",
"prism-themes",
"anchor-navigation-ex"
],
"pluginsConfig": {
"prism": {
"css": [
"prism-themes/themes/prism-base16-ateliersulphurpool.light.css"
]
},
"anchor-navigation-ex": {
"showLevel": true,
"associatedWithSummary": true,
"mode": "float",
"float": {
"showLevelIcon": false,
"level1Icon": "fa fa-hand-o-right",
"level2Icon": "fa fa-hand-o-right",
"level3Icon": "fa fa-hand-o-right"
},
"pageTop": {
"showLevelIcon": false,
"level1Icon": "fa fa-hand-o-right",
"level2Icon": "fa fa-hand-o-right",
"level3Icon": "fa fa-hand-o-right"
}
},
"theme-default": {
"showLevel": false
}
}
}

针对SUMMARY.md举例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Summary
* [介绍](README.md)
* [使用说明](usage.md)
* [组件拆分最佳实践](best.md)
* [grain配置](config.md)
* [javascript API](api.md)
* [缓存类API](api/cache.md)
* [位置类API](api/location.md)
* [信息类API](api/clientInfo.md)
* [安全类API](api/safety.md)
* [定制界面类API](api/clientUi.md)
* [原生功能类API](api/widget.md)
* [自定义API](api/customize.md)

Markdown书写规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1. 段落与段落之间空一行表示。
分节的时候可以多空一行。单个回车视为空格,连续回车才是换行。(行尾加两个空格,可以段内强制换行,一般用户可以忽略。)
2. 其实在网络上你可以完全抛弃开头空两格的习惯,代之以段落之间空一行的习惯。如果只要要开头空两格,那么可以输入 来表示一个空格, 为两个。或者使用输入法切换到全角,双击空格键。
3. 标题:# 一级标题
“#”之后最好加一个空格,这在md单向标记中都最好使用
也可以把”=“写在标题(H1)下面的一行,表示上面一行的文字为标题,”-“写在下面便是小标题或是节标题(H2)。
4. 加粗,斜体:**加粗**,*斜体*,***粗斜体***
5. 引用:>
6. 行内源代码:‘代码'。行的开头空四个空格,缩进内容视为代码块。代码块也可以用’‘’代码‘’‘来完成。当然简单的用'代码'也可以显示。
7. 删除线:~~删除~~
8. 层次(也就是类似目录列表的东西):“*” 后面要加空格,这是必须的,除了 *,还可以使用 + 或者 -。
1. 第一节
2. 第二节
* 第一小节(推荐每层次缩进四个空格)
* 小小节 1
* 小小节 2
* 第二小节
9. 链接,图片:[想要显示的文字](链接,"Title"),![(图片说明)](图片链接)。段落内使用的时候左右各空一格,除非是使用列表的时候。
此外,还可以以索引方式把url都列在文章的最后,例如这样:
[文字][1]
[1]: 链接(不要忘记冒号后面的空格,title的写法与上类似)
10. 分割线:---,上下各空一行,也可以用***,其实只要三个以上,随便你怎么写。
11. 其他:
[链接标题][null-link],可以生成一个伪链接样式,也就是存在链接的样式,但没有实质的链接。更高级的链接写法:[文字][hover]
[hover]:链接"悬停文字"
图片链接:
[![][jane-eyre-pic][jane-eyre-douban]
[jane-eyre-pic]: http://img3.douban.com/mpic/s1108264.jpg
[jane-eyre-douban]: http://book.douban.com/subject/1141406/
若要在图片下线是说明:{ImagCap}说明{/ImgCap}
12. 跟其他的编程语言一样,利用转意字符”/“就可以输出”[“这类符号

kerkee在iOS上的快速上手指南

发表于 2016-11-03   |   分类于 kerkee   |   阅读次数

这篇文章将介绍kerkee如何在iOS上快速上手!

kerkee是一个多主体共存型Hybrid框架,具有跨平台、用户体验好、性能高、扩展性好、灵活性强、易维护、规范化、集成云服务、具有Debug环境、彻底解决跨域问题。

Github上的地址:https://github.com/kercer/kerkee_ios
OSChina上的地址:http://git.oschina.net/zihong/kerkee_ios
官网地址:http://www.kerkee.com

kerkee的native部分目前支持Android和iOS平台,两个平台的架构设计及接口设计保持一致,大大降低了跨平台的成本,下面介绍一下如何集成kerkee以及如何上手快速做出一款自己的demo

kerkee的集成有:包的方式集成和源码集成两种方式,你可以选择其中的一种方式集成

包方式集成

iOS的kerkee使用CocoaPods进行管理,在集成的时候很方便。


简述: 如果你已知道CocoaPods如何使用,你只需在Podfile中添加pod ‘kerkee’, ’~> 1.0.1’ 或者 pod ‘kerkee’,然后即可走起,此时你可不用看以下的详细说明了


CocoaPods的安装及深入使用:请点击这里

前提:cocopods安装,安装非常简单,本来想略去这一部分的,但还是贴一下命令吧,如果不明白网络上搜索一搜一大把。

1
2
sudo gem install cocoapods
pod setup

1、 创建Podfile
使用也比较简单,cd到你的工程的根目录$projectPath

1
2
cd $projectPath
pod init

这个命令就会再工程根目录下面生成一个Podfile文件,podfile用文本编辑就行了

2、 配置Podfile
在你工程的Podfile文件添加

1
pod ‘kerkee’, ’~> 1.0.1’

或者你想直接使用最新版可把版本号去掉,使用以下这句

1
pod ‘kerkee’

我帖出个podfile文件配置的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Uncomment this line to define a global platform for your project
# platform :ios, '8.0'
# Uncomment this line if you're using Swift
# use_frameworks!
target 'TestKerkeePod' do
#or this way,If it is a team work,please do not use this way.
#because it use last version of kerkee,it is a bad way
#pod ‘kerkee’
pod ‘kerkee’, ’~> 1.0.1’
end
target 'TestKerkeePodTests' do
end
target 'TestKerkeePodUITests' do
end

3、执行导入命令

使用终端cd 到你的Podfile所在的目录,然后再使用pod install就可以把这些开源库导入,CocoaPods就开始为我们做下载源码、配置依赖关系、引入需要的framework等一些列工作。

1
2
cd $projectPath
pod install --verbose

安装完,这些库都放在一个Pods的工程中,然后会用xcode的workspace来管理这个工程和你自己的工程。以后就打开yourproject.xcworkspace就行了。

至此,基本集成已完成!!!恭喜你已经集成了kerkee,接下来就代码走起!!!

源码集成

  • 1、拉取源码
    git clone https://github.com/kercer/kerkee_ios.git
    
  • 2、拷贝根目录下的kerkee目录到你的工程目录(这步也可以忽略)
  • 3、打开你的工程,把kerkee.xcodeproj文件拉到你的工程里进行lib依赖
  • 4、找到你工程的TARGETS,在Embedded Binaried添加kerkee.framework

iOS快速上手指南

简述:
只需三步即可代码快速上手

  1. 注册js与native对应的类
  2. 实现native部分与js对应的方法
  3. 创建KCWebview进行调用

以下详情说明一下如何快速上手

  • 注册对应的接口类或模块

在使用之前,你必须先注册对应的接口类或模块,使得js对象能与Native类进行映射,全局只需要注册一次就够了

1
2
3
4
5
6
7
8
9
10
//have rewritten jsBridgeClient in kerkee
//you can use this way, first you can import "KCJSDefine.h"
//[KCJSBridge registClass:[KCApiOverrideJSBridgeClient class] jsObjName:kJS_jsBridgeClient];
[KCJSBridge registJSBridgeClient:[KCApiOverrideJSBridgeClient class]];
[KCJSBridge registClass:[KCApiTest class] jsObjName:kJS_TestModule];
//you can regist class which inherit from KCJSObject,js call static function
//[KCJSBridge registClass:[KCApiJSObjExample class] jsObjName:kJS_JSObjExampleModule];
[KCJSBridge registObject:[[KCApiJSObjExample alloc]init] ];

  • 实现JS对应的Native接口

KCApiOverrideJSBridgeClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "KCApiOverrideJSBridgeClient.h"
#import "KCBaseDefine.h"
#import "KCJSBridge.h"
@implementation KCApiOverrideJSBridgeClient
+(void)testJSBrige:(KCWebView*)aWebView argList:(KCArgList*)args
{
NSString* jsonInfo = [args getString:@"info"];
KCLog(@"%@", jsonInfo);
}
+(void)commonApi:(KCWebView*)aWebView argList:(KCArgList*)args
{
NSString* jsonInfo = [args getString:@"info"];
KCLog(@"%@", jsonInfo);
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:@"OK!" forKey:@"info"];
NSString *json = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:dic options:0 error:nil] encoding:NSUTF8StringEncoding];
KCAutorelease(json);
//回调
[KCJSBridge callbackJS:aWebView callBackID:[args getObject:@"callbackId"] jsonString:json];
}
@end

KCApiTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import "KCApiTest.h"
#import "KCBaseDefine.h"
#import "KCJSBridge.h"
@implementation KCApiTest
+(void)testInfo:(KCWebView*)aWebView argList:(KCArgList*)args
{
NSString* jsonInfo = [args getString:@"testInfo"];
KCLog(@"%@", jsonInfo);
KCJSCallback* callback = [args getCallback];
if (callback)
{
[callback callbackJS:aWebView jsonString:@"{}"];
}
//也可以这么回调
//[KCJSBridge callbackJS:aWebView callBackID:[args getString:@"callbackId"] string:@"This is testInfo callball"];
}
@end

KCApiJSObjExample

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "KCApiJSObjExample.h"
#import "KCJSObjDefine.h"
@implementation KCApiJSObjExample
- (NSString*)getJSObjectName
{
return kJS_JSObjExampleModule;
}
-(void)objExampleNotStaticFunction:(KCWebView*)aWebView argList:(KCArgList*)args
{
KCLog(@"objExampleNotStaticFunction");
}
+(void)objExampleStaticFunction:(KCWebView*)aWebView argList:(KCArgList*)args
{
KCLog(@"objExampleStaticFunction");
}
@end

  • 创建KCWebView

在ViewController中,添加成员变量

1
2
3
4
5
6
@interface ViewController ()
{
KCWebView* m_webView;
KCJSBridge* m_jsBridge;
}

初始化KCWebView和KCJSBridge对象

1
2
3
4
5
m_webView = [[KCWebView alloc] initWithFrame:self.view.bounds];
//add webview in your view
[self.view addSubview:m_webView];
//you can implement webview delegate
m_jsBridge = [[KCJSBridge alloc] initWithWebView:m_webView delegate:self];
  • 实现KCWebView代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#pragma mark --
#pragma mark KCWebViewProgressDelegate
-(void)webView:(KCWebView*)webView identifierForInitialRequest:(NSURLRequest*)initialRequest
{
}
#pragma mark - UIWebView Delegate
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
NSString *scrollHeight = [aWebView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"];
NSLog(@"scrollHeight: %@", scrollHeight);
NSLog(@"webview.contentSize.height %f", aWebView.scrollView.contentSize.height);
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:aWebView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:[scrollHeight floatValue]];
// [aWebView addConstraint:heightConstraint];
NSLog(@"webview frame %@", NSStringFromCGRect(aWebView.frame));
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
}
- (BOOL)webView:(UIWebView *)aWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
return YES;
}

至此,简单Demo即可运行起来

kerkee在Android上的快速上手指南

发表于 2016-11-03   |   分类于 kerkee   |   阅读次数

kerkee是一个多主体共存型Hybrid框架,具有跨平台、用户体验好、性能高、扩展性好、灵活性强、易维护、规范化、集成云服务、具有Debug环境、彻底解决跨域问题。

Github上的地址:https://github.com/kercer/kerkee_android
OSChina上的地址:https://git.oschina.net/zihong/kerkee_android.git
官网地址:http://www.kerkee.com

kerkee的native部分目前支持Android和iOS平台,两个平台的架构设计及接口设计保持一致,大大降低了跨平台的成本,下面介绍一下如何集成kerkee以及如何上手快速做出一款自己的demo

kerkee的集成有:包的方式集成和源码集成两种方式,你可以选择其中的一种方式集成

包方式集成

前提:有Android环境,本项目现在使用的是gradle构建,IDE建议Android Studio,当然你也可以使用idea或eclipse,甚至其他。

kerkee从包方式集成,非常简单,建议使用此方式,干净简洁。

在你的Android工程的build.gradle中找到 dependencies 块,添加
compile 'com.kercer:kerkee:1.3.9'即可。

如下所示

1
2
3
4
dependencies {
compile fileTree(include: '*.jar', dir: 'libs')
compile 'com.kercer:kerkee:1.3.9'
}

源码集成

  • 1、 先拉取源码

    git clone https://github.com/kercer/kerkee_android.git
    

    源码的根目录包含kerkee和kerkee_example目录
    kerkee目录是kerkee的工程,可以直接导入工程进行lib库依赖

  • 2、把kerkee目录拷贝到自己的工程根目录(通常与你工程的setting.gradle同一目录)
  • 3、在你自己工程的setting.gradle文件中添加include ‘:kerkee’
  • 4、在你自己工程build.gradle文件的dependencies 代码块中添加compile project(':kerkee')

基于此,集成基本完成,接下来将介绍如何上手实现自己的demo

快速上手指南

简述:

只需三步即可代码快速上手

  1. 注册js与native对应的类
  2. 实现native部分与js对应的方法
  3. 创建KCWebview进行调用

以下详情说明一下如何快速上手

  • 注册对应的接口类或模块

可以参考例子中的KCRegistMgr类的实现,全局只需注册一次就够了

1
2
3
4
5
6
7
8
9
10
11
12
13
//注册类,所注册的native code中的类的函数必是静态函数,js都能调到
//第一个参数为js的类名,第二个参数为native的类名
KCJSBridge.registClass(KCJSObjDefine.kJSObj_testModule, KCApiTestModule.class);
//上层可以使用自己的类取代kerkee中的jsBridgeClient,对应的js对象类为jsBridgeClient
// KCJSBridge.registClass(KCJSDefine.kJS_jsBridgeClient, KCApiJSBridgeClient.class);//与下一行效果一致
KCJSBridge.registJSBridgeClient(KCApiJSBridgeClient.class);
//注册对象方式
//KCApiJSObjExample必须继承KCJSObject,并实现getJSObjectName()方法,返回js类名
//KCApiJSObjExample中的函数可以是静态函数也可以是成员函数,HybridRuntime会自动处理
KCJSBridge.registObject(new KCApiJSObjExample());
  • 实现JS对应的Native接口
    静态类如KCApiTestModule中的实现,修改一下方法名即可
1
2
3
public static void testInfo(final KCWebView aWebView, KCArgList aArgList)
{
}

KCApiJSObjExample(继承KCJSObject,并实现getJSObjectName()),修改一下方法名即可

1
2
3
4
5
6
7
8
9
10
//成员方法
public void objExampleNotStaticFunction(final KCWebView aWebView, KCArgList aArgList)
{
}
//静态方法
public static void objExampleStaticFunction(final KCWebView aWebView, KCArgList aArgList)
{
}
  • 创建KCWebView

在例子中提供了一个默认的KCDefaultBrowser,如果你有特殊的UI需求,你可以参照KCDefaultBrowser进行实现,这时你可以为所欲为地可以把KCWebView添加到任何view中进行呈现

所要注意的地方是:

创建KCWebView时,初始化时,若需要设置ChromeClient和WebViewClient,则注意以下两个函数的参数类型

mWebView.setWebChromeClient(KCWebChromeClient);
mWebView.setWebViewClient(KCWebViewClient)

  • 调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
//create browser that use KCWebview
KCDefaultBrowser browser = new KCDefaultBrowser(this);
View view = browser.getView();
setContentView(view);
//regist classes to JSBridge,the relationship between binding js objects and native classes
//and you can use default browser's registJSBridgeClient function
KCRegistMgr.registClass();
//you can registObject here;
//KCJSBridge.registObject(new KCTest());
browser.loadTestPage();
//browser.loadUrl("http://www.baidu.com");
}

至此,简单Demo即可运行起来

当然,你也可以直接运行官方提供的Demo,可以按以下说明进行操作
在拉取的源码根目录下有个kerkee_example,这里就是demo。
在根目录添加local.properties文件,配置你的SDK路径

1
2
sdk.dir=/Users/zihong/android-sdks
ndk.dir=/Users/zihong/android-ndk

把根目录导入到Android Studio中,这时可直接运行example

CocoaPods的使用详解

发表于 2016-11-03   |   分类于 iOS   |   阅读次数

CocoaPods是什么

CocoaPods是一个用来帮助我们管理第三方依赖库的工具,是iOS平台最常用的第三方类库管理工具,绝大部分有名的开源类库都支持CocoaPods。它可以解决库与库之间的依赖关系,下载库的源代码,同时通过创建一个Xcode的workspace来将这些第三方库和我们的工程连接起来,供我们开发使用。

使用CocoaPods的目的是让我们能自动化的、集中的、直观的管理第三方开源库。

为什么使用CocoaPods

在进行iOS开发的时候,总免不了使用第三方的开源库,比如SBJson、AFNetworking、Reachability等等。使用这些库的时候通常需要:

  • 下载开源库的源代码并引入工程
  • 向工程中添加开源库使用到的framework
  • 解决开源库和开源库以及开源库和工程之间的依赖关系、检查重复添加的framework等问题
  • 如果开源库有更新的时候,还需要将工程中使用的开源库删除,重新执行前面的三个步骤,顿时头都大了。。。

自从有了CocoaPods以后,这些繁杂的工作就不再需要我们亲力亲为了,只需要我们做好少量的配置工作,CocoaPods会为我们做好一切!

安装CocoaPods

安装

CocoaPods是用Ruby实现的,要想使用它首先需要有Ruby的环境。幸运的是OS X系统默认的已经可以运行Ruby了,因此我们只需要执行以下命令:

1
sudo gem install cocoapods

CocoaPods是以Ruby gem包的形式被安装的。在安装执行的过程中,可能会问我们是不是更新rake,输入y即可。这是因为rake gem包会在安装的过程中检查更细,如果有可用的新版本就会出现刚才的选项。

在安装进程结束的时候,执行命令:

1
pod setup

如果没有报错,就说明一切安装就成功了!

安装过程中可能遇到的问题

1、执行完install命令半天没反应

安装cocoapods执行install没反应或出下以下错误

1
2
ERROR: Could not find a valid gem 'cocoapods' (>= 0), here is why:
Unable to download data from https://rubygems.org/ - Errno::EPIPE: Broken pipe - SSL_connect (https://rubygems.org/latest_specs.4.8.gz)

这有可能是因为Ruby的默认源使用的是cocoapods.org,国内访问这个网址有时候会有问题,网上的一种解决方案是将远替换成淘宝的,替换方式如下:

1
2
3
gem sources --remove https://rubygems.org/
//等有反应之后再敲入以下命令
gem sources -a http://ruby.taobao.org/

要想验证是否替换成功了,可以执行:

1
gem sources -l

正常的输出是:

1
2
3
*** CURRENT SOURCES ***
http://ruby.taobao.org/

2、gem版本过老

gem是管理Ruby库和程序的标准包,如果它的版本过低也可能导致安装失败,解决方案自然是升级gem,执行下述命令即可:

1
sudo gem update --system

3、安装完成后,执行pod setup命令时报错:

1
2
3
4
/Users/zihong/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/rubygems/dependency.rb:298:in `to_specs': Could not find 'cocoapods' (>= 0) among 6 total gem(s) (Gem::LoadError)
from /Users/zihong/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/rubygems/dependency.rb:309:in `to_spec'
from /Users/zihong/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/rubygems/core_ext/kernel_gem.rb:53:in `gem'
from /Users/zihong/.rvm/rubies/ruby-1.9.3-p448/bin/pod:22:in `<main>'

这就是路径设置的问题,可以通过执行:

1
rvm use ruby-1.9.3-p448

解决该问题。

3、升级CocoaPods

升级很简单,再次执行安装命令即可:

1
sudo gem install cocoapods

需要注意的是,如果安装的时候使用了sudo,升级的时候一样需要使用该关键字,不然升级完了以后又会出现路径不匹配问题。

使用CocoaPods

1、 创建Podfile

使用也比较简单,cd到你的工程的根目录$projectPath

1
2
cd $projectPath
pod init

这个命令就会再工程根目录下面生成一个Podfile文件,podfile用文本编辑就行了。
你也可以使用touch Podfile进行创建Podfile

Podfile文件可以放在任意一个目录下,具体请看以下的Podfile配置

2、 配置Podfile

在你工程的Podfile文件添加

1
pod ‘kerkee’, ’~> 1.0.0’

或者你想直接使用最新版可把版本号去掉,使用以下这句

1
pod ‘kerkee’

我帖出个podfile文件配置的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Uncomment this line to define a global platform for your project
# platform :ios, '8.0'
# Uncomment this line if you're using Swift
# use_frameworks!
target 'TestKerkeePod' do
#or this way,If it is a team work,please do not use this way.
#because it use last version of kerkee,it is a bad way
#pod ‘kerkee’
pod ‘kerkee’, ’~> 1.0.0’
end
target 'TestKerkeePodTests' do
end
target 'TestKerkeePodUITests' do
end

Podfile本质上是用来描述Xcode工程中的targets用的。如果我们不显式指定Podfile对应的target,CocoaPods会创建一个名称为default的隐式target,会和我们工程中的第一个target相对应。换句话说,如果在Podfile中没有指定target,那么只有工程里的第一个target能够使用Podfile中描述的Pods依赖库。

如果想在同一个工程中的一个Podfile中同时描述project中的多个target,根据需求的不同,可以有不同的实现方式。

① 多个target中使用相同的Pods依赖库

比如,名称为TestKerkeePod的target和SecondTarget的target都需要使用Reachability、SBJson、AFNetworking、kerkee四个Pods依赖库,可以使用link_with关键字来实现,将Podfile写成如下方式:

1
2
3
4
5
6
7
8
link_with 'TestKerkeePod', 'SecondTarget'
platform :ios
pod 'Reachability', '~> 3.0.0'
pod 'SBJson', '~> 4.0.0'
pod ‘kerkee’, ’~> 1.0.0’
platform :ios, '7.0'
pod 'AFNetworking', '~> 2.0'

这种写法就实现了TestKerkeePod和SecondTarget两个target共用相同的Pods依赖库。

② 不同的target使用完全不同的Pods依赖库

TestKerkeePod这个target使用的是Reachability、SBJson、AFNetworking、kerkee四个依赖库,但SecondTarget这个target只需要使用OpenUDID这一个依赖库,这时可以使用target关键字,Podfile的描述方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
target :'TestKerkeePod' do
platform :ios
pod 'Reachability', '~> 3.0.0'
pod 'SBJson', '~> 4.0.0'
pod ‘kerkee’, ’~> 1.0.0’
platform :ios, '7.0'
pod 'AFNetworking', '~> 2.0'
end
target :'SecondTarget' do
pod 'OpenUDID', '~> 1.0.0'
end

其中,do/end作为开始和结束标识符。

关于于Podfile文件的路径

事实上Podfile文件可以放在任意一个目录下,需要做的是在Podfile中指定工程的路径,和原来相比,Podfile文件就在最开始的位置增加了一行,具体内容如下:

1
2
3
4
5
6
7
8
9
xcodeproj "/Users/zihong/Desktop/test/TestKerkeePod/TestKerkeePod.xcodeproj"
platform :ios
pod 'Reachability', '~> 3.0.0'
pod 'SBJson', '~> 4.0.0'
pod ‘kerkee’, ’~> 1.0.0’
platform :ios, '7.0'
pod 'AFNetworking', '~> 2.0'

指定路径使用的是xcodeproj关键字。

此后,进入Podfile文件所在路径,执行pod install命令(往下文看)就会和之前一样下载这些Pods依赖库,而且生成的相关文件都放在了Podfile所在目录下面。

3、执行导入命令

使用终端cd 到你的Podfile所在的目录,然后再使用pod install就可以把这些开源库导入,CocoaPods就开始为我们做下载源码、配置依赖关系、引入需要的framework等一些列工作。

1
2
cd $projectPath
pod install --verbose

可以看到,工程的根目录下多了三个东西:yourproject.xcworkspace、Podfile.lock文件和Pods目录

安装完,这些库都放在一个Pods的工程中,然后会用xcode的workspace来管理这个工程和你自己的工程。以后就打开yourproject.xcworkspace就行了。

说明

对于工程发生的变化,有几点需要说明:

  • 第三方库会被编译成静态库供我们正真的工程使用

CocoaPods会将所有的第三方库以target的方式组成一个名为Pods的工程,该工程就放在刚才新生成的Pods目录下。整个第三方库工程会生成一个名称为libPods.a的静态库提供给我们自己的CocoaPodsTest工程使用。

  • 我们的工程和第三方库所在的工程会由一个新生成的workspace管理

为了方便我们直观的管理工程和第三方库,我们的工程和Pods工程会被以workspace的形式组织和管理,也就是我们刚才看到的yourproject.xcworkspace文件。

原来的工程设置已经被更改了,这时候我们直接打开原来的工程文件去编译就会报错,只能使用新生成的workspace来进行项目管理。

  • 如果上面因为权限问题安装失败,必须每次都要删除
1
rm -rf /Users/zihong/Library/Caches/CocoaPods/

因为这个缓存中会存下你的github的东西,造成每次都调用上次权限问题的缓存。

  • 关于Podfile文件编辑时,第三方库版本号的各种写法:
1
2
3
4
5
6
7
8
9
pod ‘AFNetworking’ //不显式指定依赖库版本,表示每次都获取最新版本
pod ‘AFNetworking’, ‘2.0’ //只使用2.0版本
pod ‘AFNetworking’, ‘>2.0′ //使用高于2.0的版本
pod ‘AFNetworking’, ‘>=2.0′ //使用大于或等于2.0的版本
pod ‘AFNetworking’, ‘<2.0′ //使用小于2.0的版本
pod ‘AFNetworking’, ‘<=2.0′ //使用小于或等于2.0的版本
pod ‘AFNetworking’, ‘~>0.1.2′ //使用大于等于0.1.2但小于0.2的版本,相当于>=0.1.2并且<0.2.0
pod ‘AFNetworking’, ‘~>0.1′ //使用大于等于0.1但小于1.0的版本
pod ‘AFNetworking’, ‘~>0′ //高于0的版本,写这个限制和什么都不写是一个效果,都表示使用最新版本
  • 关于Podfile.lock文件

上文讲过,在开始使用CocoaPods,执行完pod install之后,会生成一个Podfile.lock文件。这个文件看起来跟我们关系不大,实际上绝对不应该忽略它。

该文件用于保存已经安装的Pods依赖库的版本,通过CocoaPods安装了SBJson、AFNetworking、Reachability三个POds依赖库以后对应的Podfile.lock文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
PODS:
- AFNetworking (2.1.0):
- AFNetworking/NSURLConnection
- AFNetworking/NSURLSession
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/UIKit
- AFNetworking/NSURLConnection (2.1.0):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/NSURLSession (2.1.0):
- AFNetworking/NSURLConnection
- AFNetworking/Reachability (2.1.0)
- AFNetworking/Security (2.1.0)
- AFNetworking/Serialization (2.1.0)
- AFNetworking/UIKit (2.1.0):
- AFNetworking/NSURLConnection
- Reachability (3.0.0)
- SBJson (4.0.0)
DEPENDENCIES:
- AFNetworking (~> 2.0)
- Reachability (~> 3.0.0)
- SBJson (~> 4.0.0)
SPEC CHECKSUMS:
AFNetworking: c7d7901a83f631414c7eda1737261f696101a5cd
Reachability: 500bd76bf6cd8ff2c6fb715fc5f44ef6e4c024f2
SBJson: f3c686806e8e36ab89e020189ac582ba26ec4220
COCOAPODS: 0.29.0

Podfile.lock文件最大得用处在于多人开发。对于没有在Podfile中指定Pods依赖库版本的写法,如下:

1
pod 'SBJson'

该句话用于获取当前SBJson这个Pods依赖库的最新版本。

当团队中的某个人执行完pod install命令后,生成的Podfile.lock文件就记录下了当时最新Pods依赖库的版本,这时团队中的其它人check下来这份包含Podfile.lock文件的工程以后,再去执行pod install命令时,获取下来的Pods依赖库的版本就和最开始用户获取到的版本一致。

如果没有Podfile.lock文件,后续所有用户执行pod install命令都会获取最新版本的SBJson,这就有可能造成同一个团队使用的依赖库版本不一致,这对团队协作来说绝对是个灾难!

在这种情况下,如果团队想使用当前最新版本的SBJson依赖库,有两种方案:

更改Podfile,使其指向最新版本的SBJson依赖库;

执行pod update命令;

鉴于Podfile.lock文件对团队协作如此重要,我们需要将它添加到版本管理中。

CocoaPods常用命令

  • 1、pod install

根据Podfile文件指定的内容,安装依赖库,如果有Podfile.lock文件而且对应的Podfile文件未被修改,则会根据Podfile.lock文件指定的版本安装。

每次更新了Podfile文件时,都需要重新执行该命令,以便重新安装Pods依赖库。

  • 2、pod update

若果Podfile中指定的依赖库版本不是写死的,当对应的依赖库有了更新,无论有没有Podfile.lock文件都会去获取Podfile文件描述的允许获取到的最新依赖库版本。

  • 3、pod search

命令格式为:

1
$ pod search OpenUDID

后面的OpenUDID为参数。

从命令的名称不难看出,该命令是用来按名称搜索可用的Pods依赖库,执行结果如下:

1
2
3
4
5
6
-> OpenUDID (1.0.0)
Open source initiative for a universal and persistent UDID solution for iOS.
pod 'OpenUDID', '~> 1.0.0'
- Homepage: http://OpenUDID.org
- Source: https://github.com/ylechelle/OpenUDID.git
- Versions: 1.0.0 [master repo]

这里我们搜到了一条可用数据,里面描述了OpenUDID库的简要信息。其实我们真正需要的是上述结果中的第三行:

1
pod 'OpenUDID', '~> 1.0.0'

不难看出,这是我们需要添加到Podfile文件中的。

有了这条命令,就可以方便、迅速地找到需要的Pods依赖库。

  • 4、pod setup
    命令格式为:
1
pod setup

执行完了以后会打印:

1
2
3
4
Setting up CocoaPods master repo
Updating 7cd4668..f3d3ced
Fast-forward

接下来还会打印很多更新信息。

这条命令用于跟新本地电脑上的保存的Pods依赖库tree。由于每天有很多人会创建或者更新Pods依赖库,这条命令执行的时候会相当慢,还请耐心等待。我们需要经常执行这条命令,否则有新的Pods依赖库的时候执行pod search命令是搜不出来的。

kerkee简介

发表于 2016-11-03   |   分类于 kerkee   |   阅读次数

kerkee框架的诞生背景

Hybrid App兼具了Native App的所有优势,也兼具了Web App使用HTML5跨平台开发低成本的优势。以及具有使用Native扩展Web接口以弥补web无法调用平台性API等优势。Hybrid App也是未来客户端技术的发展趋势。HTML5的出现,市面上已有很多应用(如淘宝、百度搜索、高德地图)使用了Hybrid App的开发模式,但遇到了一些瓶颈(如性能不如预期,无法操作浏览器内部数据流程,无法自定义请求的需求),用户体验没有预期的好。
基于此,一种新一开发模式诞生了!Kerkee框架是市面上独一无二的多主体共存的灵活混合型开发模型。

kerkee框架是什么

Kerkee是一个多主体共存型Hybrid框架,具有跨平台、用户体验好、性能高、扩展性好、灵活性强、易维护、规范化、集成云服务、具有Debug环境、彻底解决跨域问题。

kerkee官网

  • 官网: http://www.kerkee.com

  • github: https://github.com/kercer

  • QQ交流群: 110710084

使用kerkee案例

Kerkee的Hybrid架构思想已使用在两款亿级用户量及多款千万级用户量的APP上

  • UC游戏大厅
  • 九游游戏中心
  • 天翼导航
  • 搜狐新闻客户端
  • 搜狐News SDK(已应用到搜狐视频客户端中)
  • 斗米客户端(B端、C端)

基于kerkee框架的开发模式

从开发者角度来说,它支持三种的团队开发模式:

  1. 针对Web开发者

    这种模式其中的一个场景是:只会Web开发,却不会Native开发的开发者提供了一系列的平台型接口。这种方式具有开发周期短,跨平台等优点。
  2. 针对Native开发者

    这种开发模式的其中一个场景是:Native开发者想要截获Web页面的数据或者对数据进行自己的处理,或者Web页面中的行为进行修改。在这个时候,Kerkee框架将会为他们带来便利。
  3. 针对Web开发者和Native团队共同合作的开发团队

    对于这种模式的团队,kerkee框架具体更开放更透明的协作,并且严格地隔离各自职责。各得Web团队和Native团队把主要精力定位到各自的模块上,有利于各自的模块优化到极致。

kerkee框架特性和能解决的问题

  1. 跨平台

    kerkee是Hybrid App框架,业务HTML5开发,HTML5具备了跨平台的特性,因此Kerkee也具备了跨平台的特性。
  2. 用户体验好

    所有的web接口都可在Native自定义实现,即Web UI或数据操作上若满足不了用户体验,皆可通原生的代码进行实现,以达到较佳的用户体验。
  3. 性能高

    在性能方面,kerkee框架做了大量的优化,底层网络层、IO操作等皆采用C/C++实现,并且重写了WebView,对Web中资源(如图片资源等)的控制,以事件驱动模型实现资源请求,并且实现一套针对Web的缓存策略,完全抛离webview那一套数据流程的操作。使开发者具有更透明的数据操作,以达到更佳的性能,并且突破了原有开发模式下的性能瓶颈。
  4. 扩展性好

    kerkee框架采用插件式模块化设计,每个模块即为一个webapp,在需要时可自由扩展。
  5. 灵活性强

    kerkee内部实现runtime,自动把js接口转化了native接口,Web层与Native层严格隔离达到无耦合状态,开发者对整个流程和接口都是开放透明,无特殊约束。
  6. 易维护

    Kerkee框架使客户端严格模块化,使用了接口式的交互模型,具有动态更新特性,易于维护,便以运营。
  7. 规范化

    Kerkee框架符合W3C标准,重新实现了XMLHttpRequest、WebSocket、LocalStorage、Application Cache等HTML5特性。Web前端开发者只需按W3C标准编写代码即可,即一次编写,到处运行的原则,无任何第三方库依赖。
  8. Debug工具

    Kerkee内部集成Debug环境,web端log将会打印到控制台或文件中
  9. 彻底解决跨域

    Kerkee框架采用一套特殊机制,解决了跨域问题,也就是说开发者可以操作互联网上任何一个Web页面的数据。
  10. 使客户端架构更清晰

    Kerkee框架会使得客户端的架构更为清晰。整体结构,自上而下分层如下图所示:

    client

  11. 使用简便

    对于开发者来说,使用简便。

    Web开发者:无需添加其他代码,只需要按W3C规范实现代码即可。若要调用Native接口,只需要调用框架中对应的fuction即可。

    Native开发者:只需要把对应的类注册到Kerkee中即可,代码量不超过5行便可使用Kerkee框架

NodeJS工程化部署方案

发表于 2016-11-03   |   分类于 架构设计   |   阅读次数

背景概述

在前端技术快速发展的今天,前端项目越来越多基于NodeJS,如NodeOS、Ghost blog等。单项目的部署也比较简单,直接 node xx.js命令即可搞定,如果要让Node项目在后台运行,可以使用forever、nohup等工具实现。但又面临了几个问题,如何让node项目开机自启动;部署多个node项目时,如何工程化一键守护;如何让新增项目扩展灵活。带着这两个问题,今天介绍下如何实现NodeJS工程化部署方案。

forever的安装

记得加-g,forever要求安装到全局环境下

1
sudo npm install forever -g

#forever的使用
网络上有很多使用教程,我这里收集并罗列常用的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 简单的启动
forever start app.js
// 指定forever信息输出文件,当然,默认它会放到~/.forever/forever.log
forever start -l forever.log app.js
// 指定app.js中的日志信息和错误日志输出文件
// -o 就是console.log输出的信息,-e 就是console.error输出的信息
forever start -o out.log -e err.log app.js
// 追加日志,forever默认是不能覆盖上次的启动日志,
// 所以如果第二次启动不加-a,则会不让运行
forever start -l forever.log -a app.js
// 监听当前文件夹下的所有文件改动
forever start -w app.js
// 显示所有运行的服务
forever list
// 停止所有运行的node App
forever stopall
// 停止其中一个node App
forever stop app.js
// 当然还可以这样
// forever list 找到对应的id,然后:
forever stop [id]
// 重启所有
forever restartall
// 开发和线上建议配置
// 开发环境下
NODE_ENV=development forever start -l forever.log -e err.log -a app.js
// 线上环境下
NODE_ENV=production forever start -l ~/.forever/forever.log -e ~/.forever/err.log -w -a app.js

工程化方案

创建守护脚本

创建sh目录,用来专门存放脚本的目录,当然,你也可以放到其他目录

1
mkdir ~/sh

编写一个启动脚本nodeforever.sh,放到 ~/sh 目录下

1
2
cd ~/sh
vim nodeforever.sh

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/bin/bash
### BEGIN INIT INFO
# Provides: zihong
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
# chkconfig: 345 88 08
# description: Forever for Node.js
export PATH=$PATH:/usr/local/bin #在这里指定一下Node的可执行程序安装目录,我的是/usr/local/bin
export NODE_PATH=$NODE_PATH:/usr/local/lib/node_modules #这里是Node类库的路径
#LOG=/data/log/nodeforever/node.log #可选,日志文件目录
DIRPATH=/data/nodeforever //项目的启动文件都放在这个目录
cd $DIRPATH
#a=`find . -type l |xargs ls -l|awk -F '->' '{print $2}'`
#echo $a
node=node
forever=forever
filelist=`ls $DIRPATH`
for file in $filelist
do
DEAMON=$file #这里需要填写你自己的Node项目的启动脚本文件
PID=$DIRPATH/.pid/$DEAMON.pid #必填内容,用于记录forever的进程号
echo -e "\nbegin >>>>>>>>> $DEAMON"
echo "node path:$NODE_PATH"
#node=node
#forever=forever
LOG=/data/log/nodeforever/$DEAMON.log #可选,日志文件目录
case "$1" in
start)
NODE_ENV=production $forever start -l $LOG --pidFile $PID -a $DEAMON
;;
stop)
$forever stop --pidFile $PID $DEAMON
;;
stopall)
$forever stopall --pidFile $PID
;;
restartall)
$forever restartall --pidFile $PID
;;
reload|restart)
$forever restart -l $LOG --pidFile $PID -a $DEAMON
;;
list)
$forever list
exit 1
;;
*)
echo -e "\033[31m Usage: /etc.init.d/node {start|stop|restart|reload|stopall|restartall|list} \033[0m"
exit 1
;;
esac
done
exit 0

保存,并给nodeforever.sh设置权限

1
chmod 755 nodeforever.sh

创建软链接到init.d目录

1
ln -s ~/sh/nodeforever.sh /etc/rc.d/init.d/nodeforever

添加脚本

1
chkconfig --add nodeforever

系统启动时自启动

1
chkconfig --level 345 nodeforever on

编辑rc.local文件

1
vim /etc/rc.d/rc.local

在rc.local中也添加个启动命令

1
service nodeforever start

至此,守护脚本已创建完毕

项目部署

项目部署比较简单,所有Node项目的xx.js文件都软链接到nodeforever.sh中指定的/data/nodeforever/目录下集中管理即可。完成后,若要立即生效,可以重启nodeforever服务,或者重启服务器

1
service nodeforever restart

当有新增Node项目时,只要把项目的xx.js软链接到/data/nodeforever/下即可,至于软链接过来的文件名称随便起,只要在该目录下不重名即可

URD协议

发表于 2016-11-03   |   分类于 架构设计   |   阅读次数

背景

为了提高App运营推广的灵活度,也即是app能够在任何地方、任何场景下被调起,以及调起指定的页面(已注册URI的页面),或多app之间传输数据,专为终端制定了一个URD协议,URD协议是App内及APP间页面跳转的核心通道。

URD支持跨平台,可实现端间跳转、端内跳转

协议

基于URI

URD协议将沿用URI的规范,即RFC 3986规范,文档地址:http://www.ietf.org/rfc/rfc3986.txt

RFC3986中指定了以下字符为保留字符:

! * ' ( ) ; : @ & = + $ , / ? # [ ]

uri格式为 scheme://authority/path?query#fragment

其中authority格式: user-info@host:port

例如:

http://user:pass@www.example.com:1234/path?query=true#fragment

弊端

有时客户端需要支持uri嵌套url,其中一个场景如:

doumi://string/http://www.doumi.com/index.html?arg1=data1&arg2=data2

从国际规范来看,其中arg1=data1&arg2=data2应该属于外层的doumi的uri,但是有时从人为的角度认为arg1=data1&arg2=data2归属于内层的http的需求。

URD协议

定义的URD协议如下:

urd格式为 scheme://action/path-encoding?query#fragment

1、需要对path部分进行url encode,这样子path部分可传任何字符串,path为页面的指定路径,若唯一可不填。针对端外跳端内,若某action下页面唯一,可不填,以避免路径泄露

2、scheme为doumi,在客户端实现中,一个scheme就是一个注册器

3、authority部分,也就是action用来指定行为动作。

string字段(通用类型):代表path部分为一个字符串,此字符串可以是任何的协议或字符串。转到到首页

子鸿

子鸿

8 日志
4 分类
8 标签
RSS
zihong kercer
© 2015 - 2017 子鸿