Freeline適配kotlin-2-kotlin增量實現(xiàn)

github鏈接

Freeline適配kotlin-2 源碼修改

在上一部分我們梳理了java增量的邏輯

整體來講就是:

  • 掃描變化的java文件
  • 對它們進行單獨的javac編譯
  • 然后打包成增量dex
  • merge進去

其實現(xiàn)在大家基本上已經(jīng)有思路了

javac換成kotlinc就ok了嘛

磨刀霍霍向牛羊

打開我心愛的pycharm

1.增加對kotlin修改的掃描

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

現(xiàn)在保存修改文件狀態(tài)的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這個方法我們在上一節(jié)就已經(jīng)介紹了 先檢查修改時間在檢查md5

這些操作后 我們修改一個kotlin文件 然后跑一遍freeline的調(diào)試模式

{
    "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數(shù)組里面已經(jīng)出現(xiàn)了我們修改的文件了

我們下一步要做的就是:對它進行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增量沒有什么區(qū)別 因為沒有加入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的字節(jié)碼文件是單獨存放的 需要把那些字節(jié)碼文件也納入到classpath中來

然后把kotlin增量的操作添加到freeline執(zhí)行的操作鏈上

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))

其實就已經(jīng)很清晰了 增量kotlinc然后把字節(jié)碼存放到freeline文件夾 然后再統(tǒng)一dex打增量包 推送到手機

Dex增量打包

Dex增量工具會自己把字節(jié)碼文件夾的生成字節(jié)碼打包 而我們適配kotlin要做的是

設置標志位 為什么呢?

因為之前增量dex的標志位只針對了java的情況 修改kotlin并不能觸發(fā)標志位的變化

所以只改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混寫的相互依賴什么的 還有各種蜜汁問題

不過一個優(yōu)秀的增量工具就是這樣子一步步走下來的

希望這篇文章可以對你有所啟發(fā)

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容