Freeline适配kotlin-2-kotlin增量实现

github链接

Freeline适配kotlin-2 源码修改

在上一部分我们梳理了java增量的逻辑

整体来讲就是:

  • 扫描变化的java文件
  • 对它们进行单独的javac编译
  • 然后打包成增量dex
  • merge进去

其实现在大家基本上已经有思路了

javac换成kotlinc就ok了嘛

磨刀霍霍向牛羊

打开我心爱的pycharm

1.增加对kotlin修改的扫描

self._changed_files[module_name] = {'libs': [], 'assets': [], 'res': [], 'src': [], 'manifest': [],
                                    'config': [], 'so': [], 'cpp': [], 'kotlin': []}
# kotlin占坑

现在保存修改文件状态的map里面增加kotlin字段 准备放置修改的kotlin的文件路径

然后我们修改扫描代码文件修改的方法

# scan src
src_dirs = self._config['project_source_sets'][module_name]['main_src_directory']
for src_dir in src_dirs:
    if os.path.exists(src_dir):
        for dirpath, dirnames, files in os.walk(src_dir):
            if re.findall(r'[/\\+]androidTest[/\\+]', dirpath) or '/.' in dirpath:
                continue
            for fn in files:
              # 之前只有对java后缀名文件的检查
                if fn.endswith('java'):
                    if fn.endswith('package-info.java') or fn.endswith('BuildConfig.java'):
                        continue
                    fpath = os.path.join(dirpath, fn)
                    if self.__check_changes(module_name, fpath, module_cache):
                        self._changed_files[module_name]['src'].append(fpath)
                # 添加kotlin的增量检查
                elif fn.endswith('kt'):
                    fpath = os.path.join(dirpath, fn)
                    if self.__check_changes(module_name, fpath, module_cache):
                        self._changed_files[module_name]['kotlin'].append(fpath)

check_changes这个方法我们在上一节就已经介绍了 先检查修改时间在检查md5

这些操作后 我们修改一个kotlin文件 然后跑一遍freeline的调试模式

{
    "build_info": {
        "last_clean_build_time": 1503822329.0,
        "is_root_config_changed": false
    },
    "projects": {
        "app": {
            "src": [],
            "so": [],
            "assets": [],
            "kotlin": [
                "/Users/retrox/AndroidStudioProjects/One/app/src/main/java/com/twtstudio/one/view/VActivity.kt"
            ],
            "libs": [],
            "res": [],
            "config": [],
            "cpp": [],
            "manifest": []
        }
    }
}

在kotlin数组里面已经出现了我们修改的文件了

我们下一步要做的就是:对它进行kotlinc

对kt文件单独增量编译

流程类似于对java的增量

新建一个TaskCommand类用于对kotlin的增量编译

class GradleIncKotlincCommand(IncKotlincCommand):
    def __init__(self, module_name, invoker):
        IncKotlincCommand.__init__(self, module_name, invoker)

    def execute(self):
        self._invoker.check_r_md5()  # check if R.java has changed
        # self._invoker.check_other_modules_resources()
        should_run_kotlinc_task = self._invoker.check_kotlinc_task()
        if not should_run_kotlinc_task:
            self.debug('no need to execute kotlinc ')
            return

        self.debug('start to execute kotlinc command...')
        self._invoker.append_r_file()
        self._invoker.fill_classpaths()
        self._invoker.clean_dex_cache()
        self._invoker.run_kotlinc_task()

其实和java增量没有什么区别 因为没有加入kotlin的复杂特性支持(如kapt)所以某种角度看比java增量还简单

然后我们看看run_kotlinc_task这个方法

#运行增量kotlinc
def run_kotlinc_task(self):
    kotlincargs = self._generate_kotlin_compile_args()
    self.debug('kotlinc exec: ' + ' '.join(kotlincargs))
    output, err, code = cexec(kotlincargs, callback=None)

    if code != 0:
        raise FreelineException('incremental kotlinc compile failed.', '{}\n{}'.format(output, err))
    

这个方法只贴了核心代码 当然还有一些R文件的增量什么的需要处理下(我只展示和kotlin相关的部分)

到了_generate_kotlin_compile_args这个方法

#kotlin增量命令的生成 暂时直接kotlinc了
def _generate_kotlin_compile_args(self, extra_javac_args_enabled=False):
    # javacargs = [self._javac]
    # test environment kotlinc
    kotlincargs = ['kotlinc']
    arguments = []
    arguments.append('-cp')
    # todo  适配classpath
    self._classpaths.append('${projectDir}/app/build/tmp/kotlin-classes/debug')
    arguments.append(os.pathsep.join(self._classpaths))

    for fpath in self._changed_files['kotlin']:
        arguments.append(fpath)

    arguments.append('-d')
    arguments.append(self._finder.get_patch_classes_cache_dir())

    kotlincargs.extend(arguments)
    return kotlincargs

kotlin的classpath要增加一些 因为kotlin的字节码文件是单独存放的 需要把那些字节码文件也纳入到classpath中来

然后把kotlin增量的操作添加到freeline执行的操作链上

class GradleCompileCommand(CompileCommand):
    def __init__(self, module, invoker):
        self._module = module
        CompileCommand.__init__(self, 'gradle_{}_compile_command'.format(module), invoker)

    def _setup(self):
        # 加一个kotlin即可
        self.add_command(GradleIncKotlincCommand(self._module, self._invoker))
        self.add_command(GradleIncJavacCommand(self._module, self._invoker))
        self.add_command(GradleIncDexCommand(self._module, self._invoker))

其实就已经很清晰了 增量kotlinc然后把字节码存放到freeline文件夹 然后再统一dex打增量包 推送到手机

Dex增量打包

Dex增量工具会自己把字节码文件夹的生成字节码打包 而我们适配kotlin要做的是

设置标志位 为什么呢?

因为之前增量dex的标志位只针对了java的情况 修改kotlin并不能触发标志位的变化

所以只改kotlin的话 dex是拒接增量打包推送的

所以我们要小小的修改下

def _mark_changed_flag(self):
    info = self._changed_files.values()
    cache_dir = self._config['build_cache_dir']
    for bundle in info:
        if not android_tools.is_src_changed(cache_dir) and len(bundle['src']) > 0:
            android_tools.mark_src_changed(cache_dir)
        if not android_tools.is_res_changed(cache_dir) and len(bundle['res']) > 0:
            android_tools.mark_res_changed(cache_dir)
        # kotlin增量flag
        if not android_tools.is_src_changed(cache_dir) and len(bundle['kotlin']) > 0:
            android_tools.mark_src_changed(cache_dir)

然后修改下kotlin 跑下freeline 成功增量!

freeline兼容适配之路还有很长要走

不如kapt kotlin和java混写的相互依赖什么的 还有各种蜜汁问题

不过一个优秀的增量工具就是这样子一步步走下来的

希望这篇文章可以对你有所启发

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容