Created
November 3, 2021 18:53
-
-
Save JUSTINMKAUFMAN/6627c3c8571563b36efc9c832f6fa2b1 to your computer and use it in GitHub Desktop.
Kotlin Multiplatform Build Gradle Task for iOS/macOS Universal Framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Kotlin Multiplatform Universal XCFramework Task | |
* | |
* Description: | |
* If your project needs to target *all* possible | |
* iOS and macOS variants (including Apple Silicon | |
* hardware, ARM64 iPhone simulators, and so on), | |
* this task will build the frameworks, lipo those | |
* that can be combined into a single binary, and | |
* place them where Xcode expects to find them in | |
* an XCFramework bundle. | |
* | |
* Usage: | |
* Copy everything in this file to the bottom of | |
* your target project's build.gradle.kts file | |
* and execute the `buildUniversalFramework` task | |
* (which you can find in the "Swift" task group) | |
*/ | |
// You can change this to a more Apple-friendly | |
// version of your project name (e.g. title case) | |
val frameworkName: String = project.name | |
val clearGeneratedFrameworks = tasks.create("clearGeneratedFrameworks") { | |
group = "Swift" | |
description = "Removes all Apple framework build products generated by these custom tasks" | |
delete(layout.buildDirectory.dir("bin/ios-arm64-simulator_x86_64")) | |
delete(layout.buildDirectory.dir("bin/macos-arm64_x86_64")) | |
delete(layout.buildDirectory.dir("framework")) | |
} | |
val lipoAppleFrameworks = tasks.register("lipoAppleFrameworks") { | |
group = "Swift" | |
description = "Combine equivalent Apple platform target binaries with lipo" | |
dependsOn(duplicateMacosArm64Framework) | |
doLast { | |
val macosArm64OutputFile = buildDir.resolve("bin/macosArm64/releaseFramework/${frameworkName}.framework/Versions/A/${frameworkName}") | |
val macosX64OutputFile = buildDir.resolve("bin/macosX64/releaseFramework/${frameworkName}.framework/Versions/A/${frameworkName}") | |
val iosSimulatorArm64OutputFile = buildDir.resolve("bin/iosSimulatorArm64/releaseFramework/${frameworkName}.framework/${frameworkName}") | |
val iosX64OutputFile = buildDir.resolve("bin/iosX64/releaseFramework/${frameworkName}.framework/${frameworkName}") | |
mkdir("build/bin/macos-arm64_x86_64") | |
exec { | |
commandLine( | |
"lipo", | |
"-create", | |
macosArm64OutputFile.path, | |
macosX64OutputFile.path, | |
"-output", | |
buildDir.resolve("${frameworkName}MacOS").path | |
) | |
} | |
copy { | |
from(layout.buildDirectory.file("${frameworkName}MacOS")) | |
rename { frameworkName } | |
into(layout.buildDirectory.dir("bin/macos-arm64_x86_64/${frameworkName}.framework/Versions/A")) | |
} | |
delete(layout.buildDirectory.file("${frameworkName}MacOS")) | |
mkdir("build/bin/ios-arm64-simulator_x86_64") | |
exec { | |
commandLine( | |
"lipo", | |
"-create", | |
iosSimulatorArm64OutputFile.path, | |
iosX64OutputFile.path, | |
"-output", | |
buildDir.resolve("${frameworkName}iOS").path | |
) | |
} | |
copy { | |
from(layout.buildDirectory.dir("bin/iosSimulatorArm64/releaseFramework")) | |
into(layout.buildDirectory.dir("bin/ios-arm64-simulator_x86_64")) | |
} | |
copy { | |
from(layout.buildDirectory.file("${frameworkName}iOS")) | |
rename { frameworkName } | |
into(layout.buildDirectory.dir("bin/ios-arm64-simulator_x86_64/${frameworkName}.framework")) | |
} | |
delete(layout.buildDirectory.file("${frameworkName}iOS")) | |
} | |
} | |
val duplicateMacosArm64Framework by tasks.creating(Exec::class.java) { | |
group = "Swift" | |
description = "Creates a duplicate macOS ARM64 build to hold the combined macOS library" | |
dependsOn( | |
clearGeneratedFrameworks, | |
"linkReleaseFrameworkIosSimulatorArm64", | |
"linkReleaseFrameworkIosArm64", | |
"linkReleaseFrameworkIosX64", | |
"linkReleaseFrameworkMacosArm64", | |
"linkReleaseFrameworkMacosX64" | |
) | |
workingDir = buildDir | |
executable = "sh" | |
args("-c", """ | |
cp -R \ | |
${buildDir.resolve("bin/macosArm64/releaseFramework/").path} \ | |
${buildDir.resolve("bin/macos-arm64_x86_64/").path} | |
""".trimIndent() | |
) | |
} | |
val buildUniversalFramework by tasks.creating(Exec::class.java) { | |
group = "Swift" | |
description = "Build a Universal XCFramework for Apple platforms" | |
workingDir = buildDir | |
executable = "sh" | |
mkdir("build/framework") | |
dependsOn( | |
lipoAppleFrameworks, | |
"linkReleaseFrameworkIosX64", | |
"linkReleaseFrameworkIosArm64", | |
"linkReleaseFrameworkMacosX64" | |
) | |
args( | |
"-c", | |
listOf( | |
"""xcodebuild \""", | |
"""-create-xcframework \""", | |
"""-framework ${buildDir.resolve("bin/iosArm64/releaseFramework/${frameworkName}.framework").path} \""", | |
"""-framework ${buildDir.resolve("bin/ios-arm64-simulator_x86_64/${frameworkName}.framework").path} \""", | |
"""-framework ${buildDir.resolve("bin/macos-arm64_x86_64/${frameworkName}.framework").path} \""", | |
"-output ${buildDir.path + "/framework/${frameworkName}.xcframework"}" | |
) | |
.joinToString("\n") | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To be clear, these tasks expect the following targets to be defined in the
kotlin
block of your project: