Kotlin Multiplatform ProjectでKotlin 1.3.20に移行したら出力framework名が変わった件

Kotlin 1.3.20がリリースされたので、早速KMP(Android/iOS)なプロジェクトでバージョンアップしてみた。

ほとんど考えることはないんだけど、一箇所、KMPで対応プラットフォームを指定する箇所だけちょっと躓いた。

今まではターゲットは下記のように設定していた。

groovy
kotlin {
    targets {
        fromPreset(presets.jvm, 'jvm')
        fromPreset(presets.iosX64, 'ios') {
          compilations.main.outputKinds('FRAMEWORK')
        }
    }
}

// iOSのビルド時に呼び出されるタスク
task copyFramework {
    def buildType = project.findProperty("kotlin.build.type") ?: "DEBUG"
    def target = project.findProperty("kotlin.target") ?: "ios"
    dependsOn kotlin.targets."$target".compilations.main.linkTaskName("FRAMEWORK", buildType)

    doLast {
        def srcFile = kotlin.targets."$target".compilations.main.getBinary("FRAMEWORK", buildType)
        def targetDir = getProperty("configuration.build.dir")
        copy {
            from srcFile.parent
            into targetDir
            include 'data.framework/**'
            include 'data.framework.dSYM'
        }
    }
}

copyFrameworkタスクのほうは参考にするドキュメントによって違うだろうけど、iOSアプリをビルドするときに呼ばれる、成果物のframeworkをコピーするものだ。

で、このあたりの設定を書き換えずにビルドすると、出力されるframeworkの名前が変わってしまう。
今までは${module名}.frameworkだったのが、main.frameworkになってしまう。

iOS側の参照をすべて書き換えるのでも対応できなくはないけど、根本的な解決策ではないしちょっと気持ち悪い。

これの原因は1.3.20から導入された新しいDSLだ。
ターゲットの設定方法を1.3.20からの新しいDSLに書き換えると下記のようになり、今まで通り${module名}.frameworkな成果物が得られる。
ちなみにcopyタスクの方を書き換え忘れると存在しないタスクを参照しようとしてビルドが失敗する。

groovy
kotlin {
  jvm()
  iosX64('ios') {
    binaries {
      framework()
    }
  }
}

task copyFramework {
    def buildType = project.findProperty("kotlin.build.type") ?: "DEBUG"
    def target = project.findProperty("kotlin.target") ?: "ios"
    // 上でframeworkにnamePrefixを設定した場合はその値を第一引数に与える
    def bin = kotlin.targets."$target".compilations.main.target.binaries.findFramework("", buildType)
    dependsOn bin.linkTask

    doLast {
        def srcFile = kotlin.targets."$target".compilations.main.target.binaries.findFramework("", buildType).outputFile
        def targetDir = getProperty("configuration.build.dir")
        copy {
            from srcFile.parent
            into targetDir
            include 'data.framework/**'
            include 'data.framework.dSYM'
        }
    }
}

このDSLの変更により、一つのターゲットに対して複数の成果物を設定することができるようになったらしい。

groovy
kotlin {
  iosX64 {
    binaries {
      framework('foo')
      framework('bar') {
        export(project(":dependency"))
      }
    }
  }
}

例えば上みたいな書き方をすると、foo.frameworkbar.frameworkが出力される。
片方だけ特別な設定を加える、ということも可能だ。