修改 Gradle 插件(Plugins)的下载地址(repositories)

Gradle 也可以用下面的方式声明使用的插件:

1
2
3
4
// build.gradle
plugins {
id 'com.example.plugin', version '1.0'
}

其实是从 Gradle 官方的插件仓库 https://plugins.gradle.org/m2/ 下载的。

但是,众所周知的原因,某些地区会连不上,导致下载不到需要的插件,例如出现如下错误:

1
2
3
4
5
6
7
* What went wrong:
A problem occurred configuring root project 'MyApp'.
> Could not resolve all files for configuration ':classpath'.
> Could not download jimfs.jar (com.google.jimfs:jimfs:1.1)
> Could not get resource 'https://plugins.gradle.org/m2/com/google/jimfs/jimfs/1.1/jimfs-1.1.jar'.
> Could not HEAD 'https://plugins.gradle.org/m2/com/google/jimfs/jimfs/1.1/jimfs-1.1.jar'.
> Connect to d29vzk4ow07wi7.cloudfront.net:443 [d29vzk4ow07wi7.cloudfront.net/54.192.84.6, d29vzk4ow07wi7.cloudfront.net/54.192.84.168, d29vzk4ow07wi7.cloudfront.net/54.192.84.128, d29vzk4ow07wi7.cloudfront.net/54.192.84.173] failed: Read timed out

又或者,插件是不对外的,存在某个私有仓库的,该如何修改或者添加额外的私有仓库地址呢?

如何简单快速搭建 Android 大仓

书接上文,上回提到 B 站Android团队为了解决组件化后协作上的问题,已经采用了大仓(monorepo)的方案来组织代码。

国内实践大仓的团队少之又少,更别提 Android 的大仓了,几乎没有来自其它团队的可借鉴经验。在这条路上,我们可以算作先行者。本文粗陋,文中所列思路不可能适用所有团队,仅给同样想实践Android 大仓的人些许启发。

一个标准的 Gradle 项目

首先回顾一下 Android 项目的组织方式。自从13年开始官方逐渐迁移到 Android Studio 做为 IDE 后,Android 项目的开发和编译就绑在 Gradle 上了。

一个标准的 Gradle 项目结构如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MyApp/
├── build.gradle
├── settings.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradle.properties
└── app
├── build.gradle
└── src
└── main
├── java
├── res
└── AndroidManifest.xml

通常,会有多个Gradle Module存在:

1
2
3
4
5
6
7
8
9
10
11
12
MyApp/
├── build.gradle
├── settings.gradle
├── app
│ ├── build.gradle
│ └── src
├── lib1
│ ├── build.gradle
│ └── src
└── lib2
├── build.gradle
└── src

其中 settings.gradle 会注册所有的 Module

1
include ':app', ':lib1', ':lib2'

多仓库

随业务的扩张,Module 数量会越来越多。遵循多数人实践过的组件化的思路,按业务分仓库存放便理所当然:

1
2
3
4
5
6
7
8
9
10
11
12
13
android group/
├── MyApp/
│ ├── build.gradle
│ └── settings.gradle
├── app1/
│ ├── build.gradle
│ └── settings.gradle
├── app2/
│ ├── build.gradle
│ └── settings.gradle
└── libs/
├── build.gradle
└── settings.gradle

每个仓库都是一个标准 Gradle 项目,通过 publishing 插件将module 都上传 aar(或者jar)到 maven私服(如nexus)上,再在 MyApp/build.gradle 中以 maven 组件的形式依赖它们,最终打包成apk:

1
2
3
4
5
6
7
8
9
10
11
repositories {
maven {
name = "myRepo"
url = "http://myrepo.example.com/android"
}
}
dependencies {
implementation 'com.example.android:app-a:1.0.0'
implementation 'com.example.android:app-b:1.0.0'
implementation 'com.example.android:lib-a:1.1.0'
}

此时的代码组织方式便是上文中所述的多仓库形态(可能许多团队正处于当前阶段)。

多仓到大仓

那么,如何既能快速搭建出适用于 Android 的大仓,又能不影响当前的团队协作流程,还要尽量避免迁移带来的开发效率降低?

B 站 Android 代码库的演进历程

早在2012年,B 站 Android APP 便已上线。当时开发者不过一人,而如今,业务线众多、隶属不同团队的Android 端开发人员数以百计。从单兵作战到百花争鸣,代码库的组织管理也随之经过数次的改革、演进。

单仓库

2014年底,Android 端的常驻开发人员一只手也数的过来。业务发展迅速,为追求效率,方便管理,所有代码都在一个仓库中,甚至包括第三方的、开源的代码(个别用 git submodule 管理)。Clone下来导入 Eclipse 就可以开干。

到大约15年中旬,开始使用 Android Studio,得益于 Gradle 的项目管理理念,分出了多个 library module。外部依赖使用 maven。也是这一期间开始搭建了内网 maven 服务。

这期间代码库组织结构是:单仓库 + 个别 git submodule

这种组织方式好处显而易见:

  1. 项目结构简单:随时随地 clone 下来导入 IDE 即可以开始开发,代码所有人可见,没有额外的限制。
  2. 方便快速迭代:改动可以快速入库,适合小团队,review方便,改动透明

但是,约莫到16年中,业务发展,新团队纷纷成立,招聘要求降低人员迅速膨胀。这种小而美的代码库已经不适用了,主要有以下缺点:

  1. 代码结构混乱,模块之间依赖关系混沌:倒不如说是技术债,前期的疲于业务迭代,以及没有及时的规划出好的代码层级架构,如今人员纷杂水平不一,之前追求的“没有限制”反而诱发了恶果
  2. 编译时间变长:业务增速发展,代码量爆炸式增长,单机编译越来越慢,开发幸福感跌到谷地

Hexo 使用 DisqusJS 代理评论

博客目前用的是Hexo,没有后端,为静态博客,评论一般用的第三方系统,如常用的 Disqus。但众所周知的原因,在“火星”上无法正常访问Disqus。

隆重推荐一个通过api实现评论的项目:DisqusJS

这里说一下它的配置技巧。

添加DisqusJS 到 hexo主题

这里以很多人用的 Next 主题为例,其它类似。

修改_config.yml 中的disqus配置为:

1
2
3
4
5
6
7
8
# for DisqusJS, https://github.com/SukkaW/DisqusJS
disqus:
enable: true
shortname: #你的shortname
api: #https://disqus.com/api/
apikey: #你申请的public api key
admin: #你的名字
adminLabel: #你的特别标识

具体含义见DisqusJS

修改 layout/_partials/head/custom-head.swig

1
2
3
{% if theme.disqus.enable %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/disqusjs@0.2.5/dist/disqusjs.css">
{% endif %}

让 Terminal 和 Android Studio 使用同一个 Gradle Daemon

在同时使用 Terminal 和 Android Studio 开发和编译 Android 项目时,跑 gradle 任务经常有一个提示,类似:

Starting a Gradle Daemon, 2 incompatible Daemons could not be reused, use --status for details

这表示 Gradle 又开启了一个新的 Daemon,已经存在的没有被重用。

执行gradlew --status可以看到已经有3个Daemon 存活,对于我这台13年末产的老爷机来说是个严重的负担

1
2
3
4
5
6
7
$ ./gradlew --status
PID STATUS INFO
33346 IDLE 4.6
31842 IDLE 4.6
29669 IDLE 4.6

Only Daemons for the current Gradle version are displayed. See https://docs.gradle.org/4.6/userguide/gradle_daemon.html#sec:status

存在多个 Daemon 的原因

Gradle 官方给的解释是:

  1. Gradle 版本不一样,比如一个项目用了 Gradle 4.4 而另一个用了 Gradle 4.6;
  2. Java 版本不一样,比如一个项目使用 JDK 7 而另一个则是 JDK 8 执行的 Gradle;
  3. Daemon JVM 参数不一样,比如一个项目指定了 -Xmx1024m 而另一个 -Xmx2048m
  4. 存在的 Daemon 都处于 BUSY 状态,比如Android Studio 和 Terminal 同时跑 Gradle 任务。

如何共用一个Daemon

针对上述原因,可以得到以下方案:

对于同一个项目来说,使用同一个 JDK 执行 Gradle即可;如果是多个项目则另外需要指定使用同一个版本的gradle、并设置同样的 JVM 参数。

瞎拍(5)- 枸杞岛之旅

大王村沙滩

一直存着愿,想去看碧海蓝天,趁着 5.1 假便去舟山的枸杞岛走了一遭。

三礁江大桥

~


可惜天公不作美,小岛上一直有雾罩着,能见度不高,幻想中的海天一色,终究没看着。


~

瞎拍(4)

老家门口的油菜花开的正盛,花丛中许多蜜蜂穿梭,忍不住追着瞎拍了几张 (´・ω・`)

✿

✿

✿

✿

✿

一个小插件解决组件化引发的DEX字段数爆炸的问题

TL;DR

插件名:shrinker

项目地址: https://github.com/yrom/shrinker(其实很早之前就已经发布到github上了,不过无人问津→_→)

插件效果:与removeUnusedCode 同用可以起到最佳效果

这里有一个简单的测试项目,大部分类来自于依赖的support库,结果如下:

选项methodsfieldsclasses
原始项目22164143672563
应用shrinker 插件2197978052392
应用shrinker 并开启 removeUnusedCode1133533021274

如果应用于依赖众多的大型项目则效果惊人。

ps. 其实已经在 b站的APP 上使用很久了,插件稳定、可靠且无副作用。

原理

不论组件化或者说模块化,都有个核心思想:拆分,拆成一个又一个独立的Library。

拆分 Library 引入的问题

举个例子

现一个 APP,它为了实践组件/模块化,拆分出了 common-ui ,business-a, business-b… 依赖关系如下图所示:

R 文件生成的大致流程如下图:

其中processReleaseResources 实际是调用的 aapt工具来给每个依赖的Library都生成一个最终确定的R.java

可想而知,第一个问题: 拆分的Android Library越多,R 文件越多!

然而,Library 的 R 文件只会在最终编译成 APK 时确定字段常量值,输出 aar 时只有一个R.txt用于记录声明的资源。

假设 common-ui 声明了15个公共drawable资源,则生成的 R 文件中将有 15个相关的用于记录的字段,而且每个依赖于它的上层的library 生成的R都会有这15个同名的字段,如下图:

由此可得,第二个问题: 越底层的依赖所声明资源越多,最终生成的 R 文件越庞大 ! 因为这些字段没有得到有效内联,最终生成的DEX字段数就会严重超标。

为了解决组件/模块化进程中出现的上述两个问题,shrinker 应运而生。

《Android Kotlin 指南》中译版

虽然很可惜没有在Kotlin 刚发布的时候跟进学习,现在也还不晚~

官方很早在 Github 上发布了一个名为 android kotlin guides 的网站供 Android 开发者学习使用,但似乎没有中文版(至今没找到╮( ̄▽ ̄)╭)。

于是乎,自己动手丰衣足食。也就几个页面,将它们都翻译了一下~

链接:https://yrom.github.io/kotlin-guides/
项目:https://github.com/yrom/kotlin-guides/

又试着将一个小工具用kotlin 重写了一遍,用以实践kotlin:https://github.com/Bilibili/xpref

That’s ALL.

瞎拍(3)

又闲来无事到植物园瞎拍了几张,也不枉这秋高气爽ヽ(゚∀゚*)ノ

✿

✿

✿

✿