libgit2使用教程(十)git clone

这是一个非常重要的操作。
这是一个非常简单的接口。
这是一个没多少内容又不得不提的主题。

直接上代码

需要注意的就是不要忘记身份验证,然后就开始 clone 操作了。

最后就简单介绍一下 git_clone_options 的主要参数:

checkout_opts
checkout 的配置,如果需要的话

fetch_opts
fetch 的配置,如果需要的话

bare
0 表示标准仓库,1 表示 bare 仓库

local
决定是否拷贝目标数据库而不是 fetch 。(如果目标是在本地,直接拷贝会更快一些)

checkout_branch
切到哪个分支,如果是空使用远端默认的分支

repository_cb
在这个回调里可以自己创建一个 repository

remote_cb
在这个回调里可以自己创建一个 remote

关于 bare 这个参数,不仅仅在 clone 这个操作用到。在 init 或 open 也是同样的意思。
表示只有版本记录,没有实际的工程里的代码和文件那些东西。更具体一点就是除了 .git 这个文件夹以外啥都没有。

示例代码:sample10

libgit2使用教程(九)git fetch & pull

目前 libgit2 对 pull 操作的支持还不是太好,所以目前能找到的资料都指出 pull 操作就是先 fetch 然后再 merge 目标分支。比如要实现 git pull origin master ,就先 fetch 然后将 master 切换到 head 再将 origin master 合并到 head。

那么就先 fetch

git_remote_fetch 这个接口的后三个参数都是可以传 null 的,但是如果报了下面这个错:
authentication required but no callback set
说明远端地址需要验证身份,所以我们要设置 ssh 证书的回调。

这样就完成了 fetch 操作。so easy

prune 也是 fetch 操作的一个重要参数。表示:清理掉远端已经删除的分支对应的本地分支,有点绕,不过应该还好理解吧。具体信息可以查一下下面这个命令。
git fetch -p (或 git fetch –prune)
在代码里实现只需要在 option 参数里做一个设置:

这样就强制使用 prune 参数了。另外几个可选枚举值可以去读注释。

接下来为了实现类似 pull 的效果,就是蛋疼的合并操作了,顺便可以复习一下之前的内容。
首先将本地 master 设为 head

然后去拿 origin master 的 commit

合并

解决冲突

add 和 commit

清空状态

打完收工。

示例代码:sample9

Android 自动化批量打包精粹

在项目即将上线的时候,都会遇到这样的问题:
有好多个有自己 SDK 的商店,而且都要赶同一个档期上线。
个别商店可能会有一些独特的小需求,比如 icon 的角标、开机闪屏 logo 、或者独有的功能接口要调用。
当10个 SDK 接完8个了,第1个接入的有更新了,需要接入最新版本才给上线。最要命的是接口有变动。
双方联调,找问题,各种沟通不畅。
下一个项目这些问题再重演一遍。

所以这个事情如果要做的优雅,高逼格,高效简洁,我们应该做到:
一次接入可以让所有项目通用。
各个部分充分解耦(SDK、项目、服务器),单独接入单独调试单独测试。
渠道商店配置可以由非技术人员(市场、运营)来管理。
当然不可少的打包应该有工具自动化完成。

简简单单几句话来描述这个事情,看起来挺简单,但是仔细想想,都挺空的。所以,还是要细化一下具体的东西。

一、 一次接入所有项目通用
要实现通用,就需要有一个比较稳定的接口将功能性 SDK 封装起来。封装起来的 SDK 我们可以姑且命名为 SDK 插件,各个项目调用统一的接口,而不需要关心 SDK 插件之中的具体的 SDK 。

二、各个部分解耦
实际上稳定统一的接口就是完成了解耦的第一步,我们需要梳理清楚具体部分的划分。渠道商店的 SDK 往往都会有服务器端接口部分,用作用户校验和支付验证。所以大致可以分为三个部分:SDK 插件开发、渠道商店对接服务器、客户端使用的 API。
各部分详细的设计参考下面的示意图:
结构图

开发 SDK 插件的流程:
前提条件:模板工程、可用的 SDK 、测试服务器接口
流程:通过模板创建工程 → 接入 SDK → 测试通过 → 导出 SDK 插件
SDK开发模板
当完成这一部分的时候,SDK 的对接就可以完全不需要核心项目团队的资源来支持了。这样就实现了一定程度的解耦,而核心项目部分,不用关心这些 SDK 功能的具体实现,只要接入一个用于测试各种 SDK 功能的测试 SDK 就可以无忧了。
测试SDK
从上面两个图可以看到,独立出一个 Platform Server 平台服务器来做与 SDK 相关的对接。这样的好处是,服务器端也实现了解耦;一个平台服务器可以服务于多个项目;并且不需要项目团队拿出资源来维护这个部分。而区分不同项目不同商店渠道只要以自定义标准参数的形式,制定出一套自己的标准就可以通用于所有接入的项目了。

对于测试 SDK 的设计,有必要叨唠两句。这个东西的目的是把通过 SDK 获取的数据直接给客户端,所以有些东西可以更直接一些。比如,需要登录获取一个 user id ,这种需求直接做一个输入框或者下拉列表,直接让开发人员输入或者选择 user id,就可以了。没有必要还让测试人员走一个完整的登录流程是不是?并且这样可以随意调整需要登录的账号,方便测试。支付同理,客户端需要处理在成功时会怎样,失败时会怎样,那么直接用两个按钮,返回给客户端结果就可以了。真的没有必要还调个支付宝啥的真去走个第三方支付流程。

三、 由非技术人员管理
因为实际上对于渠道商店出包的需求都是由非技术人员(运营、市场等)发起的,所以最好由非技术人员负责管理渠道商店的参数、数据、出包等。这样不仅可以解放出一小部分技术人员的生产力,最关键的是减少了沟通造成的损耗,当运营取得渠道相关参数之后,直接在工具中填写并提交然后工具自动读取后将需求的包打出来,这样这个流程一个人就可以完成了。
这个工作流的设计的关键当然是非技术人员以什么形式来提交给工具这些参数?最好的方案,当然是有一个非常友好的界面,可以让用户根据提示正确的填写各种参数以及提交资源等。但是如果在开发资源不足的情况下,退而求其次可以考虑使用 excel 表格,一般运营人员经过简单培训也是完全可以 hold 住的,只要将标准制定的全面且完善。

四、 自动化打包
首先只打一包的话使用 ant 一个命令就可以实现,并且同时完成包括 编译 打包 混淆 签名 等完整的流程。然而,最重要的是我们要根据之前填好的数据自动打出所有我们需要的包。
要实现这个需求,单靠 ant 脚本就不太现实了,虽然理论上也是可以实现的。这里还是建议使用强逻辑型的语言实现这个程序。在最后打包的环节再调用 ant 脚本完成打包的最后一步。
这个程序大框架上看是一个很简单的流水线,可以看下面的图。然后有很多的细节需要处理,这其中的任何小细节被忽略都有可能无法良好的工作。
流水线

编译 C++ 我的习惯是只编译一次,所有包使用同一个 so 这样可以最大程度的保证编译速度。需要传给 C++ 部分的一些参数可以通过 JNI 传递,运行效率是会有一些小影响,几乎可以忽略不计,可以让打包部分的复杂度降低不少。不过确实有一些特殊情况需要在 so 文件中打入一些数据,那就根据自己的情况再具体解决了。

我习惯在打每个包之前都删掉生成文件夹 bin 和 gen ,因为曾经有发生过不少次因为之前的生成文件的存在导致后来的改动并没有被编译进生成文件中。并且不要忘记,如果项目有引入 Library 的话,最好递归的去清理一些。

在对工程做任何改动之前都不要忘记做现场的保护。我的做法是,如果是对一个已经存在的文件做修改,我会把那个文件做备份和操作记录。再这个包打完或者出问题被中断后可以把现场恢复到最初的状态;如果是加入一个新的文件也要记录下来,在打完这个包将其删除。这样做可以最大程度的保障不会让当前操作污染到以后的事情。

可能有人注意到了,流水线这张图并没有提到 SDK Plugin 。实际上我赞成把 SDK Plugin 看做一个实体,只是为了描述更方便,理解更直观一些,具体存在形式最好是根据自己系统的情况量身定制。它可以只是散乱的一堆代码和一堆资源,也可以是其他合适的形式甚至是代码片段或者 patches ,如何使用需要根据自己的情况具体问题具体分析,而这个流水线图展示的是最纯粹的重要工作节点。

引入 Library 只需要修改 project.properties 中的 android.library.reference.* 参数,当然不要忘了在后边添加新的之前要先解析一下旧的,取到一个当前数字再添加新的数字。然而为什么是这个文件呢?它的秘密都在 build.xml 这个默认的 ant 脚本文件里,这个文件的注释读一读可以获得好多重要的信息。

默认的 ant 构建系统是需要自己生成 local.properties 这个文件,并且设定 sdk.dir 来显示指出 Android SDK 的路径。我喜欢把 build.xml 做个小改动,让这个变量直接访问环境变量:

不管是选择使用传统的 local.properties 还是修改 build.xml ,都必须要保证所有引入的 library 都有一份。我选择修改 build.xml 这个做法就是为了在不同环境中不用再多修改一个文件。

每一个渠道商店的包都必然会有一些常量参数,而使用这些参数的大多是相关的 SDK 。所以我的方案是生成一个常量类写到代码文件中替换掉之前埋在工程中用于测试的那个类。而这里最好将生成后的类做个 log,以便在出包后可以再检查一下数据是否有误,毕竟打错参数这种事情有时候并不容易被测试发现。

有许多 SDK 都会有要求在 AndroidManifest.xml 加一些东西,比如,声明 Activity、 Receiver 、权限等等,也有包括包名、版本号这些需要修改的东西。所以读写这个 xml 也是这个工具必不可少的一部分。那么数据是从哪里来的呢?首先,参数类的数据,肯定是从配置信息里获取的(包名、版本号、其他参数等);然后,与 SDK 有关的,肯定是不能让非技术人员来配置的,这部分就要作为 SDK Plugin 的一部分,可以在 SDK Plugin 中放一个专属这个 SDK 的 xml 配置,在这一步的时候从里边读取与工程中的 AndroidManifest.xml 合并。(有人选择使用替换特殊标示的方式来操作这个文件,这样的话就需要提前在这个文件里写很多特殊标识符,其后果是这个工程可能就不能直接编译运行调试了。想运行一下还需要先替换标识符感觉就有点累了,所以我认为还是读写 xml 是最靠谱的方案)

写 AndroidManifest.xml 的时候经常会遇到命名空间不见了的情况,表现为原文件的 android:xxxx 变成了 ns0:xxxx 。原因就是原来的 xml 命名空间被丢掉了,修改这个文件一定不要忘记手动设置一下 manifest 的命名空间:
xmlns:android=”http://schemas.android.com/apk/res/android”

签名的配置修改 ant.properties 这个文件,key.store 这个变量就是签名文件的路径,不过签名文件是需要提前生成好的,这个常打包的同学应该并不陌生,这里就不展开了。

要强调的一点是 .properties 文件写中文的话是会出错的,这个文件的编码是 ascii 所以如果传入的路径或文件名有包含非 ascii 字符的话,是需要转换成 \u4e00 这种形式的编码的。

libgit2使用教程(八)git remote

从这篇开始进入到有网络的 libgit2 世界,如何添加远端服务器,如何 fetch ,pull ,push 你的版本库等等,将会陆续往下写。这一篇主要介绍如何实现:
git remote
git remote add <…>
git remote delete <…>

首先我们必须要掌握如何知道我们的 remote 操作是否成功。使用文本编辑器打开一个 clone 下来的仓库的 config 文件[.git/config],可以看到这样一个条目:

[remote “origin”]
        url = git@github.com:XiaochenFTX/libgit2_samples.git
        fetch = +refs/heads/*:refs/remotes/origin/*

origin 是 remote 的名字,url 是它的远端地址。那么 fetch 后边那一串是什么呢?它表示的是在 fetch 操作的时候,数据从哪来,到哪里去。以冒号分开两个 refspec 前边表示从哪来[远端的refspec],后边表示到哪去[本地的refspec]。
关于 refspec 有一篇挺不错的文章,直接看下面这个链接:
http://docs.pythontab.com/github/gitbook/Git-Internals/The-Refspec.html
官方原文:
https://git-scm.com/book/en/v2/Git-Internals-The-Refspec

当然,在本地直接初始化的仓库是没有一个条目的。所以我们需要自己去添加一个:

这个代码我们执行之后再去看 config 文件,remote 这条就出现了。我现在用的这个版本貌似有个 bug,如果是第一次调用 git_remote_create 会出现两个 [remote “origin2″] 一个放 url 一个放 fetch ,但是如果删除之后,再调用 create 的话 url 和 fetch 就都在第一个 [remote “origin”] 下面了。
这个接口会填写默认的 fetch ,如果需要自己设置,使用下面的代码:

 

通过 git_remote_list 接口来列出所有的 remote :

 

删除一个 remote :

 

接下来简单介绍一下如何使用 ssh 方式的 url 。用 git_remote_connect 来检验是否可以成功连接。
我们知道使用 ssh 方式连接,必须要有一个 ssh key 用于身份验证。这个 key 怎么传给接口呢?找了半天最后发现,这个奇葩的接口是通过回调的方式传个证书给回调参数。

这个回调是这样的:

通过 git_cred_ssh_key_new 来生成证书。如果是使用 github 这种在服务器填写公钥的方式,那么我们就将本地对应的私钥传入就可以了。
这里还有个 bug 要注意,如果不是使用这个接口正确的生成证书,可能会出现 connect 操作卡死的情况。
另外,如果使用 ssh 格式的 url [git@github.com:XiaochenFTX/libgit2_samples.git] 在 connect 的时候报了这个错:
Unsupported URL protocol
那么很有可能是没有找到 libssh2 这个库,请先确保这个库已经正常安装了。

示例代码:sample8

libgit2 版本升级到 0.24.1后发现 git_remote_connect 这个参数多了一个,已经在代码中做了更新。如果是用的老版本库的用户看到了这篇教程,请参考对应版本的函数声明。