Generate podspec for XCFramework suitable for publishing
#KT-47812 #KT-47633 #KT-43815 #KT-42630 #KT-42105 #KT-48808 Merge-request: KT-MR-4483
This commit is contained in:
committed by
Space
parent
7493914a52
commit
cd9d74b029
+98
-14
@@ -162,7 +162,7 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
fun testPodspecMultiple() = doTestPodspec(
|
fun testPodspecMultiple() = doTestPodspec(
|
||||||
cocoapodsMultipleKtPods,
|
cocoapodsMultipleKtPods,
|
||||||
mapOf("kotlin-library" to null, "second-library" to null),
|
mapOf("kotlin-library" to null, "second-library" to null),
|
||||||
mapOf("kotlin-library" to kotlinLibraryPodspecContent(), "second-library" to secondLibraryPodspecContent()),
|
mapOf("kotlin-library" to kotlinLibraryPodspecContent(), "second-library" to secondLibraryPodspecContent("second_library")),
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -324,7 +324,7 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
}.also { writeText(it) }
|
}.also { writeText(it) }
|
||||||
}
|
}
|
||||||
hooks.addHook {
|
hooks.addHook {
|
||||||
assertContains("Cocoapods Integration requires version of this project to be specified.")
|
assertContains("Cocoapods Integration requires pod version to be specified.")
|
||||||
}
|
}
|
||||||
|
|
||||||
project.build(POD_IMPORT_TASK_NAME, "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
project.build(POD_IMPORT_TASK_NAME, "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||||
@@ -863,8 +863,8 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
val framework = fileInWorkingDir("build/cocoapods/framework/cocoapods.framework/cocoapods")
|
val framework = fileInWorkingDir("build/cocoapods/framework/cocoapods.framework/cocoapods")
|
||||||
with(runProcess(listOf("file", framework.absolutePath), projectDir)) {
|
with(runProcess(listOf("file", framework.absolutePath), projectDir)) {
|
||||||
assertTrue(isSuccessful)
|
assertTrue(isSuccessful)
|
||||||
assertTrue(output.contains("\\(for architecture armv7\\):\\s+current ar archive random librar".toRegex()))
|
assertTrue(output.contains("\\(for architecture armv7\\):\\s+current ar archive".toRegex()))
|
||||||
assertTrue(output.contains("\\(for architecture arm64\\):\\s+current ar archive random library".toRegex()))
|
assertTrue(output.contains("\\(for architecture arm64\\):\\s+current ar archive".toRegex()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -925,6 +925,60 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
project.testWithWrapper(":compileIosMainKotlinMetadata")
|
project.testWithWrapper(":compileIosMainKotlinMetadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPodPublishing() {
|
||||||
|
hooks.addHook {
|
||||||
|
assertTasksExecuted(":podPublishReleaseXCFramework")
|
||||||
|
assertTasksExecuted(":podPublishDebugXCFramework")
|
||||||
|
assertFileExists("build/cocoapods/publish/release/cocoapods.xcframework")
|
||||||
|
assertFileExists("build/cocoapods/publish/debug/cocoapods.xcframework")
|
||||||
|
assertFileExists("build/cocoapods/publish/release/cocoapods.podspec")
|
||||||
|
assertFileExists("build/cocoapods/publish/debug/cocoapods.podspec")
|
||||||
|
val actualPodspecContentWithoutBlankLines = fileInWorkingDir("build/cocoapods/publish/release/cocoapods.podspec").readText()
|
||||||
|
.lineSequence()
|
||||||
|
.filter { it.isNotBlank() }
|
||||||
|
.joinToString("\n")
|
||||||
|
|
||||||
|
assertEquals(publishPodspecContent, actualPodspecContentWithoutBlankLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.testWithWrapper(":podPublishXCFramework")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPodPublishingWithCustomProperties() {
|
||||||
|
|
||||||
|
with(project.gradleBuildScript()) {
|
||||||
|
appendToCocoapodsBlock("name = \"CustomPod\"")
|
||||||
|
appendToCocoapodsBlock("version = \"2.0\"")
|
||||||
|
appendToCocoapodsBlock("publishDir = projectDir.resolve(\"CustomPublishDir\")")
|
||||||
|
appendToCocoapodsBlock("license = \"'MIT'\"")
|
||||||
|
appendToCocoapodsBlock("authors = \"{ 'Kotlin Dev' => 'kotlin.dev@jetbrains.com' }\"")
|
||||||
|
appendToCocoapodsBlock("extraSpecAttributes[\"social_media_url\"] = \"'https://twitter.com/kotlin'\"")
|
||||||
|
appendToCocoapodsBlock("extraSpecAttributes[\"vendored_frameworks\"] = \"'CustomFramework.xcframework'\"")
|
||||||
|
appendToCocoapodsBlock("extraSpecAttributes[\"libraries\"] = \"'xml'\"")
|
||||||
|
addPod(defaultPodName)
|
||||||
|
}
|
||||||
|
|
||||||
|
hooks.addHook {
|
||||||
|
assertTasksExecuted(":podPublishReleaseXCFramework")
|
||||||
|
assertTasksExecuted(":podPublishDebugXCFramework")
|
||||||
|
assertFileExists("CustomPublishDir/release/cocoapods.xcframework")
|
||||||
|
assertFileExists("CustomPublishDir/debug/cocoapods.xcframework")
|
||||||
|
assertFileExists("CustomPublishDir/release/CustomPod.podspec")
|
||||||
|
assertFileExists("CustomPublishDir/debug/CustomPod.podspec")
|
||||||
|
val actualPodspecContentWithoutBlankLines = fileInWorkingDir("CustomPublishDir/release/CustomPod.podspec").readText()
|
||||||
|
.lineSequence()
|
||||||
|
.filter { it.isNotBlank() }
|
||||||
|
.joinToString("\n")
|
||||||
|
|
||||||
|
assertEquals(publishPodspecCustomContent, actualPodspecContentWithoutBlankLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.testWithWrapper(":podPublishXCFramework")
|
||||||
|
}
|
||||||
|
|
||||||
// paths
|
// paths
|
||||||
|
|
||||||
private fun CompiledProject.url() = externalSources().resolve("url")
|
private fun CompiledProject.url() = externalSources().resolve("url")
|
||||||
@@ -1411,18 +1465,17 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
spec.name = 'kotlin_library'
|
spec.name = 'kotlin_library'
|
||||||
spec.version = '1.0'
|
spec.version = '1.0'
|
||||||
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
spec.source = { :http=> ''}
|
||||||
spec.authors = ''
|
spec.authors = ''
|
||||||
spec.license = ''
|
spec.license = ''
|
||||||
spec.summary = 'CocoaPods test library'
|
spec.summary = 'CocoaPods test library'
|
||||||
spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework"
|
spec.vendored_frameworks = 'build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework'
|
||||||
spec.libraries = "c++"
|
spec.libraries = 'c++'
|
||||||
spec.module_name = "#{spec.name}_umbrella"
|
|
||||||
spec.dependency 'pod_dependency', '1.0'
|
spec.dependency 'pod_dependency', '1.0'
|
||||||
spec.dependency 'subspec_dependency/Core', '1.0'
|
spec.dependency 'subspec_dependency/Core', '1.0'
|
||||||
spec.pod_target_xcconfig = {
|
spec.pod_target_xcconfig = {
|
||||||
'KOTLIN_PROJECT_PATH' => ':kotlin-library',
|
'KOTLIN_PROJECT_PATH' => ':kotlin-library',
|
||||||
'PRODUCT_MODULE_NAME' => 'kotlin_library',
|
'PRODUCT_MODULE_NAME' => '${frameworkName ?: "kotlin_library"}',
|
||||||
}
|
}
|
||||||
spec.script_phases = [
|
spec.script_phases = [
|
||||||
{
|
{
|
||||||
@@ -1451,16 +1504,15 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
spec.name = 'second_library'
|
spec.name = 'second_library'
|
||||||
spec.version = '1.0'
|
spec.version = '1.0'
|
||||||
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
spec.source = { :http=> ''}
|
||||||
spec.authors = ''
|
spec.authors = ''
|
||||||
spec.license = ''
|
spec.license = ''
|
||||||
spec.summary = 'CocoaPods test library'
|
spec.summary = 'CocoaPods test library'
|
||||||
spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "second_library"}.framework"
|
spec.vendored_frameworks = 'build/cocoapods/framework/${frameworkName ?: "second_library"}.framework'
|
||||||
spec.libraries = "c++"
|
spec.libraries = 'c++'
|
||||||
spec.module_name = "#{spec.name}_umbrella"
|
|
||||||
spec.pod_target_xcconfig = {
|
spec.pod_target_xcconfig = {
|
||||||
'KOTLIN_PROJECT_PATH' => ':second-library',
|
'KOTLIN_PROJECT_PATH' => ':second-library',
|
||||||
'PRODUCT_MODULE_NAME' => 'second_library',
|
'PRODUCT_MODULE_NAME' => '${frameworkName ?: "kotlin_library"}',
|
||||||
}
|
}
|
||||||
spec.script_phases = [
|
spec.script_phases = [
|
||||||
{
|
{
|
||||||
@@ -1484,6 +1536,38 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
end
|
end
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
|
private val publishPodspecContent = """
|
||||||
|
Pod::Spec.new do |spec|
|
||||||
|
spec.name = 'cocoapods'
|
||||||
|
spec.version = '1.0'
|
||||||
|
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||||
|
spec.source = { :http=> ''}
|
||||||
|
spec.authors = ''
|
||||||
|
spec.license = ''
|
||||||
|
spec.summary = 'CocoaPods test library'
|
||||||
|
spec.vendored_frameworks = 'cocoapods.xcframework'
|
||||||
|
spec.libraries = 'c++'
|
||||||
|
spec.ios.deployment_target = '13.5'
|
||||||
|
end
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
private val publishPodspecCustomContent = """
|
||||||
|
Pod::Spec.new do |spec|
|
||||||
|
spec.name = 'CustomPod'
|
||||||
|
spec.version = '2.0'
|
||||||
|
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||||
|
spec.source = { :http=> ''}
|
||||||
|
spec.authors = { 'Kotlin Dev' => 'kotlin.dev@jetbrains.com' }
|
||||||
|
spec.license = 'MIT'
|
||||||
|
spec.summary = 'CocoaPods test library'
|
||||||
|
spec.ios.deployment_target = '13.5'
|
||||||
|
spec.dependency 'AFNetworking'
|
||||||
|
spec.social_media_url = 'https://twitter.com/kotlin'
|
||||||
|
spec.vendored_frameworks = 'CustomFramework.xcframework'
|
||||||
|
spec.libraries = 'xml'
|
||||||
|
end
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
+36
-22
@@ -9,6 +9,7 @@ import org.gradle.api.DefaultTask
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.Task
|
import org.gradle.api.Task
|
||||||
import org.gradle.api.file.FileTree
|
import org.gradle.api.file.FileTree
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||||
@@ -110,7 +111,7 @@ private fun Project.registerAssembleXCFrameworkTask(
|
|||||||
"XCFramework"
|
"XCFramework"
|
||||||
)
|
)
|
||||||
return registerTask(taskName) { task ->
|
return registerTask(taskName) { task ->
|
||||||
task.baseName = xcFrameworkName
|
task.baseName = provider { xcFrameworkName }
|
||||||
task.buildType = buildType
|
task.buildType = buildType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,7 @@ private fun Project.registerAssembleFatForXCFrameworkTask(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return registerTask(taskName) { task ->
|
return registerTask(taskName) { task ->
|
||||||
task.destinationDir = fatFrameworkDir(xcFrameworkName, buildType).resolve(appleTarget.targetName)
|
task.destinationDir = XCFrameworkTask.fatFrameworkDir(project, xcFrameworkName, buildType, appleTarget)
|
||||||
task.baseName = xcFrameworkName.asValidFrameworkName()
|
task.baseName = xcFrameworkName.asValidFrameworkName()
|
||||||
task.onlyIf {
|
task.onlyIf {
|
||||||
task.frameworks.size > 1
|
task.frameworks.size > 1
|
||||||
@@ -138,23 +139,16 @@ private fun Project.registerAssembleFatForXCFrameworkTask(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Project.fatFrameworkDir(
|
|
||||||
xcFrameworkName: String,
|
|
||||||
buildType: NativeBuildType
|
|
||||||
) = buildDir
|
|
||||||
.resolve("fat-framework")
|
|
||||||
.resolve(buildType.getName())
|
|
||||||
.resolve(xcFrameworkName)
|
|
||||||
|
|
||||||
abstract class XCFrameworkTask : DefaultTask() {
|
abstract class XCFrameworkTask : DefaultTask() {
|
||||||
/**
|
/**
|
||||||
* A base name for the XCFramework.
|
* A base name for the XCFramework.
|
||||||
*/
|
*/
|
||||||
@Input
|
@Input
|
||||||
var baseName: String = project.name
|
var baseName: Provider<String> = project.provider { project.name }
|
||||||
|
|
||||||
private val xcFrameworkName: String
|
@get:Internal
|
||||||
get() = baseName.asValidFrameworkName()
|
internal val xcFrameworkName: Provider<String>
|
||||||
|
get() = baseName.map { it.asValidFrameworkName() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A build type of the XCFramework.
|
* A build type of the XCFramework.
|
||||||
@@ -189,11 +183,11 @@ abstract class XCFrameworkTask : DefaultTask() {
|
|||||||
*/
|
*/
|
||||||
@get:Internal // We take it into account as an input in the buildType and baseName properties.
|
@get:Internal // We take it into account as an input in the buildType and baseName properties.
|
||||||
protected val fatFrameworksDir: File
|
protected val fatFrameworksDir: File
|
||||||
get() = project.fatFrameworkDir(xcFrameworkName, buildType)
|
get() = fatFrameworkDir(project, xcFrameworkName.get(), buildType)
|
||||||
|
|
||||||
@get:OutputDirectory
|
@get:OutputDirectory
|
||||||
protected val outputXCFrameworkFile: File
|
protected val outputXCFrameworkFile: File
|
||||||
get() = outputDir.resolve(buildType.getName()).resolve("$xcFrameworkName.xcframework")
|
get() = outputDir.resolve(buildType.getName()).resolve("${xcFrameworkName.get()}.xcframework")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the specified frameworks in this XCFramework.
|
* Adds the specified frameworks in this XCFramework.
|
||||||
@@ -214,10 +208,13 @@ abstract class XCFrameworkTask : DefaultTask() {
|
|||||||
val group = frameworks.filter { it.konanTarget in appleTarget.targets }
|
val group = frameworks.filter { it.konanTarget in appleTarget.targets }
|
||||||
when {
|
when {
|
||||||
group.size == 1 -> {
|
group.size == 1 -> {
|
||||||
group.first().outputFile
|
XCFrameworkFile(group.first().outputFile, group.first().isStatic)
|
||||||
}
|
}
|
||||||
group.size > 1 -> {
|
group.size > 1 -> {
|
||||||
fatFrameworksDir.resolve(appleTarget.targetName).resolve("$xcFrameworkName.framework")
|
XCFrameworkFile(
|
||||||
|
fatFrameworksDir.resolve(appleTarget.targetName).resolve("${xcFrameworkName.get()}.framework"),
|
||||||
|
group.all { it.isStatic }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -225,20 +222,37 @@ abstract class XCFrameworkTask : DefaultTask() {
|
|||||||
createXCFramework(frameworksForXCFramework, outputXCFrameworkFile, buildType)
|
createXCFramework(frameworksForXCFramework, outputXCFrameworkFile, buildType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createXCFramework(frameworks: List<File>, output: File, buildType: NativeBuildType) {
|
private data class XCFrameworkFile (val file: File, val isStatic: Boolean)
|
||||||
|
|
||||||
|
private fun createXCFramework(frameworkFiles: List<XCFrameworkFile>, output: File, buildType: NativeBuildType) {
|
||||||
if (output.exists()) output.deleteRecursively()
|
if (output.exists()) output.deleteRecursively()
|
||||||
|
|
||||||
val cmdArgs = mutableListOf("xcodebuild", "-create-xcframework")
|
val cmdArgs = mutableListOf("xcodebuild", "-create-xcframework")
|
||||||
frameworks.forEach { framework ->
|
frameworkFiles.forEach { frameworkFile ->
|
||||||
cmdArgs.add("-framework")
|
cmdArgs.add("-framework")
|
||||||
cmdArgs.add(framework.path)
|
cmdArgs.add(frameworkFile.file.path)
|
||||||
if (buildType == NativeBuildType.DEBUG) {
|
if (buildType == NativeBuildType.DEBUG && frameworkFile.isStatic.not()) {
|
||||||
cmdArgs.add("-debug-symbols")
|
cmdArgs.add("-debug-symbols")
|
||||||
cmdArgs.add(framework.path + ".dSYM")
|
cmdArgs.add(frameworkFile.file.path + ".dSYM")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmdArgs.add("-output")
|
cmdArgs.add("-output")
|
||||||
cmdArgs.add(output.path)
|
cmdArgs.add(output.path)
|
||||||
project.exec { it.commandLine(cmdArgs) }
|
project.exec { it.commandLine(cmdArgs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal companion object {
|
||||||
|
fun fatFrameworkDir(
|
||||||
|
project: Project,
|
||||||
|
xcFrameworkName: String,
|
||||||
|
buildType: NativeBuildType,
|
||||||
|
appleTarget: AppleTarget? = null
|
||||||
|
) = project.buildDir
|
||||||
|
.resolve("fat-framework")
|
||||||
|
.resolve(buildType.getName())
|
||||||
|
.resolve(xcFrameworkName)
|
||||||
|
.resolveIfNotNull(appleTarget?.targetName)
|
||||||
|
|
||||||
|
private fun File.resolveIfNotNull(relative: String?): File = if (relative == null) this else this.resolve(relative)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+26
-34
@@ -11,6 +11,7 @@ import org.gradle.api.Action
|
|||||||
import org.gradle.api.Named
|
import org.gradle.api.Named
|
||||||
import org.gradle.api.NamedDomainObjectSet
|
import org.gradle.api.NamedDomainObjectSet
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.plugins.ExtensionAware
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.gradle.util.ConfigureUtil
|
import org.gradle.util.ConfigureUtil
|
||||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
@@ -18,38 +19,26 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.Cocoapods
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary
|
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable
|
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
open class CocoapodsExtension(private val project: Project) {
|
open class CocoapodsExtension(private val project: Project) {
|
||||||
@get:Input
|
/**
|
||||||
val version: String
|
* Configure version of the pod
|
||||||
get() {
|
*/
|
||||||
require(project.version != Project.DEFAULT_VERSION) { """
|
var version: String? = null
|
||||||
Cocoapods Integration requires version of this project to be specified.
|
|
||||||
Please, add line 'version = "<version>"' to project's build file.
|
|
||||||
For more details, please, see https://guides.cocoapods.org/syntax/podspec.html#version
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
return project.version.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure authors of the pod built from this project.
|
* Configure authors of the pod built from this project.
|
||||||
*/
|
*/
|
||||||
@Optional
|
|
||||||
@Input
|
|
||||||
var authors: String? = null
|
var authors: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure existing file `Podfile`.
|
* Configure existing file `Podfile`.
|
||||||
*/
|
*/
|
||||||
@Optional
|
|
||||||
@InputFile
|
|
||||||
var podfile: File? = null
|
var podfile: File? = null
|
||||||
|
|
||||||
@get:Input
|
|
||||||
internal var needPodspec: Boolean = true
|
internal var needPodspec: Boolean = true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,30 +55,38 @@ open class CocoapodsExtension(private val project: Project) {
|
|||||||
useLibraries = true
|
useLibraries = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:Input
|
|
||||||
internal var useLibraries: Boolean = false
|
internal var useLibraries: Boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure name of the pod built from this project.
|
||||||
|
*/
|
||||||
|
var name: String = project.name.asValidFrameworkName()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure license of the pod built from this project.
|
* Configure license of the pod built from this project.
|
||||||
*/
|
*/
|
||||||
@Optional
|
|
||||||
@Input
|
|
||||||
var license: String? = null
|
var license: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure description of the pod built from this project.
|
* Configure description of the pod built from this project.
|
||||||
*/
|
*/
|
||||||
@Optional
|
|
||||||
@Input
|
|
||||||
var summary: String? = null
|
var summary: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure homepage of the pod built from this project.
|
* Configure homepage of the pod built from this project.
|
||||||
*/
|
*/
|
||||||
@Optional
|
|
||||||
@Input
|
|
||||||
var homepage: String? = null
|
var homepage: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure location of the pod built from this project.
|
||||||
|
*/
|
||||||
|
var source: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure other podspec attributes
|
||||||
|
*/
|
||||||
|
var extraSpecAttributes: MutableMap<String, String> = mutableMapOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure framework of the pod built from this project.
|
* Configure framework of the pod built from this project.
|
||||||
*/
|
*/
|
||||||
@@ -102,16 +99,12 @@ open class CocoapodsExtension(private val project: Project) {
|
|||||||
configure.execute(this)
|
configure.execute(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
|
||||||
val ios: PodspecPlatformSettings = PodspecPlatformSettings("ios")
|
val ios: PodspecPlatformSettings = PodspecPlatformSettings("ios")
|
||||||
|
|
||||||
@Nested
|
|
||||||
val osx: PodspecPlatformSettings = PodspecPlatformSettings("osx")
|
val osx: PodspecPlatformSettings = PodspecPlatformSettings("osx")
|
||||||
|
|
||||||
@Nested
|
|
||||||
val tvos: PodspecPlatformSettings = PodspecPlatformSettings("tvos")
|
val tvos: PodspecPlatformSettings = PodspecPlatformSettings("tvos")
|
||||||
|
|
||||||
@Nested
|
|
||||||
val watchos: PodspecPlatformSettings = PodspecPlatformSettings("watchos")
|
val watchos: PodspecPlatformSettings = PodspecPlatformSettings("watchos")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,27 +126,26 @@ open class CocoapodsExtension(private val project: Project) {
|
|||||||
/**
|
/**
|
||||||
* Configure custom Xcode Configurations to Native Build Types mapping
|
* Configure custom Xcode Configurations to Native Build Types mapping
|
||||||
*/
|
*/
|
||||||
@Input
|
|
||||||
val xcodeConfigurationToNativeBuildType: MutableMap<String, NativeBuildType> = mutableMapOf(
|
val xcodeConfigurationToNativeBuildType: MutableMap<String, NativeBuildType> = mutableMapOf(
|
||||||
"Debug" to NativeBuildType.DEBUG,
|
"Debug" to NativeBuildType.DEBUG,
|
||||||
"Release" to NativeBuildType.RELEASE
|
"Release" to NativeBuildType.RELEASE
|
||||||
)
|
)
|
||||||
|
|
||||||
@get:Nested
|
/**
|
||||||
|
* Configure output directory for pod publishing
|
||||||
|
*/
|
||||||
|
var publishDir: File = CocoapodsBuildDirs(project).publish
|
||||||
|
|
||||||
internal val specRepos = SpecRepos()
|
internal val specRepos = SpecRepos()
|
||||||
|
|
||||||
private val _pods = project.container(CocoapodsDependency::class.java)
|
private val _pods = project.container(CocoapodsDependency::class.java)
|
||||||
|
|
||||||
// For some reason Gradle doesn't consume the @Nested annotation on NamedDomainObjectContainer.
|
|
||||||
@get:Nested
|
|
||||||
val podsAsTaskInput: List<CocoapodsDependency>
|
val podsAsTaskInput: List<CocoapodsDependency>
|
||||||
get() = _pods.toList()
|
get() = _pods.toList()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of pod dependencies.
|
* Returns a list of pod dependencies.
|
||||||
*/
|
*/
|
||||||
// Already taken into account as a task input in the [podsAsTaskInput] property.
|
|
||||||
@get:Internal
|
|
||||||
val pods: NamedDomainObjectSet<CocoapodsDependency>
|
val pods: NamedDomainObjectSet<CocoapodsDependency>
|
||||||
get() = _pods
|
get() = _pods
|
||||||
|
|
||||||
|
|||||||
+116
-2
@@ -6,6 +6,7 @@
|
|||||||
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
|
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
|
||||||
package org.jetbrains.kotlin.gradle.plugin.cocoapods
|
package org.jetbrains.kotlin.gradle.plugin.cocoapods
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.Plugin
|
import org.gradle.api.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
@@ -18,10 +19,13 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.addExtension
|
import org.jetbrains.kotlin.gradle.plugin.addExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.*
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable
|
import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleSdk
|
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleSdk
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkTask
|
||||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.*
|
import org.jetbrains.kotlin.gradle.targets.native.tasks.*
|
||||||
import org.jetbrains.kotlin.gradle.tasks.*
|
import org.jetbrains.kotlin.gradle.tasks.*
|
||||||
@@ -57,6 +61,8 @@ internal class CocoapodsBuildDirs(val project: Project) {
|
|||||||
val externalSources: File
|
val externalSources: File
|
||||||
get() = root.resolve("externalSources")
|
get() = root.resolve("externalSources")
|
||||||
|
|
||||||
|
val publish: File = root.resolve("publish")
|
||||||
|
|
||||||
fun externalSources(fileName: String) = externalSources.resolve(fileName)
|
fun externalSources(fileName: String) = externalSources.resolve(fileName)
|
||||||
|
|
||||||
fun fatFramework(buildType: NativeBuildType) =
|
fun fatFramework(buildType: NativeBuildType) =
|
||||||
@@ -359,8 +365,12 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
it.group = TASK_GROUP
|
it.group = TASK_GROUP
|
||||||
it.description = "Generates a podspec file for CocoaPods import"
|
it.description = "Generates a podspec file for CocoaPods import"
|
||||||
it.needPodspec = project.provider { cocoapodsExtension.needPodspec }
|
it.needPodspec = project.provider { cocoapodsExtension.needPodspec }
|
||||||
|
it.publishing.set(false)
|
||||||
it.pods.set(cocoapodsExtension.pods)
|
it.pods.set(cocoapodsExtension.pods)
|
||||||
it.version = project.provider { cocoapodsExtension.version }
|
it.version.set(cocoapodsExtension.version ?: project.version.toString())
|
||||||
|
it.specName.set(cocoapodsExtension.name)
|
||||||
|
it.extraSpecAttributes.set(cocoapodsExtension.extraSpecAttributes)
|
||||||
|
it.outputDir.set(project.projectDir)
|
||||||
it.homepage.set(cocoapodsExtension.homepage)
|
it.homepage.set(cocoapodsExtension.homepage)
|
||||||
it.license.set(cocoapodsExtension.license)
|
it.license.set(cocoapodsExtension.license)
|
||||||
it.authors.set(cocoapodsExtension.authors)
|
it.authors.set(cocoapodsExtension.authors)
|
||||||
@@ -435,7 +445,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
|
|
||||||
project.tasks.register(family.toPodGenTaskName, PodGenTask::class.java) {
|
project.tasks.register(family.toPodGenTaskName, PodGenTask::class.java) {
|
||||||
it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
||||||
it.podspec = podspecTaskProvider.map { task -> task.outputFileProvider.get() }
|
it.podspec = podspecTaskProvider.map { task -> task.outputFile }
|
||||||
it.useLibraries = project.provider { cocoapodsExtension.useLibraries }
|
it.useLibraries = project.provider { cocoapodsExtension.useLibraries }
|
||||||
it.specRepos = project.provider { cocoapodsExtension.specRepos }
|
it.specRepos = project.provider { cocoapodsExtension.specRepos }
|
||||||
it.family = family
|
it.family = family
|
||||||
@@ -550,6 +560,109 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun registerPodXCFrameworkTask(
|
||||||
|
project: Project,
|
||||||
|
cocoapodsExtension: CocoapodsExtension,
|
||||||
|
buildType: NativeBuildType
|
||||||
|
): TaskProvider<XCFrameworkTask> =
|
||||||
|
with(project) {
|
||||||
|
registerTask("podPublish${buildType.name.toLowerCase().capitalize()}XCFramework") { task ->
|
||||||
|
multiplatformExtension.supportedTargets().all { target ->
|
||||||
|
target.binaries.matching { it.buildType == buildType }.withType(Framework::class.java) { framework ->
|
||||||
|
task.from(framework)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task.outputDir = cocoapodsExtension.publishDir
|
||||||
|
task.buildType = buildType
|
||||||
|
task.baseName = project.provider { cocoapodsExtension.frameworkNameInternal }
|
||||||
|
task.description = "Produces ${buildType.name.toLowerCase().capitalize()} XCFramework for all requested targets"
|
||||||
|
task.group = TASK_GROUP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerPodspecPublishTask(
|
||||||
|
project: Project,
|
||||||
|
cocoapodsExtension: CocoapodsExtension,
|
||||||
|
xcFrameworkTask: TaskProvider<XCFrameworkTask>,
|
||||||
|
buildType: NativeBuildType
|
||||||
|
): TaskProvider<PodspecTask> =
|
||||||
|
with(project) {
|
||||||
|
val task = tasks.register("podSpec${buildType.name.toLowerCase().capitalize()}", PodspecTask::class.java) { task ->
|
||||||
|
task.description = "Generates podspec for ${buildType.name.toLowerCase().capitalize()} XCFramework publishing"
|
||||||
|
task.outputDir.set(xcFrameworkTask.map { it.outputDir.resolve(it.buildType.getName()) })
|
||||||
|
task.needPodspec = provider { true }
|
||||||
|
task.publishing.set(true)
|
||||||
|
task.pods.set(cocoapodsExtension.pods)
|
||||||
|
task.specName.set(cocoapodsExtension.name)
|
||||||
|
task.version.set(cocoapodsExtension.version ?: version.toString())
|
||||||
|
task.extraSpecAttributes.set(cocoapodsExtension.extraSpecAttributes)
|
||||||
|
task.homepage.set(cocoapodsExtension.homepage)
|
||||||
|
task.license.set(cocoapodsExtension.license)
|
||||||
|
task.authors.set(cocoapodsExtension.authors)
|
||||||
|
task.summary.set(cocoapodsExtension.summary)
|
||||||
|
task.source.set(cocoapodsExtension.source)
|
||||||
|
task.frameworkName = provider { cocoapodsExtension.frameworkNameInternal }
|
||||||
|
task.ios = provider { cocoapodsExtension.ios }
|
||||||
|
task.osx = provider { cocoapodsExtension.osx }
|
||||||
|
task.tvos = provider { cocoapodsExtension.tvos }
|
||||||
|
task.watchos = provider { cocoapodsExtension.watchos }
|
||||||
|
val generateWrapper = project.findProperty(GENERATE_WRAPPER_PROPERTY)?.toString()?.toBoolean() ?: false
|
||||||
|
if (generateWrapper) {
|
||||||
|
task.dependsOn(":wrapper")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xcFrameworkTask.dependsOn(task)
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerPodPublishFatFrameworkTasks(
|
||||||
|
project: Project,
|
||||||
|
xcFrameworkTask: TaskProvider<XCFrameworkTask>,
|
||||||
|
buildType: NativeBuildType
|
||||||
|
) =
|
||||||
|
with(project) {
|
||||||
|
multiplatformExtension.supportedTargets().all { target ->
|
||||||
|
target.binaries.matching { it.buildType == buildType }.withType(Framework::class.java) { framework ->
|
||||||
|
|
||||||
|
val appleTarget = AppleTarget.values().firstOrNull { it.targets.contains(target.konanTarget) } ?: return@withType
|
||||||
|
val fatFrameworkTaskName =
|
||||||
|
"pod${buildType.name.toLowerCase().capitalize()}${appleTarget.targetName.capitalize()}FatFramework"
|
||||||
|
val fatFrameworkTask = if (fatFrameworkTaskName in tasks.names) {
|
||||||
|
tasks.named(fatFrameworkTaskName, FatFrameworkTask::class.java)
|
||||||
|
} else {
|
||||||
|
tasks.register(fatFrameworkTaskName, FatFrameworkTask::class.java) { fatTask ->
|
||||||
|
fatTask.baseName = framework.baseName
|
||||||
|
fatTask.destinationDir = XCFrameworkTask.fatFrameworkDir(this, fatTask.fatFrameworkName, buildType, appleTarget)
|
||||||
|
fatTask.onlyIf {
|
||||||
|
fatTask.frameworks.size > 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fatFrameworkTask.configure {
|
||||||
|
it.from(framework)
|
||||||
|
}
|
||||||
|
|
||||||
|
xcFrameworkTask.dependsOn(fatFrameworkTask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerPodPublishTasks(project: Project, cocoapodsExtension: CocoapodsExtension) {
|
||||||
|
|
||||||
|
val xcFrameworkTasks = NativeBuildType.values().map { buildType ->
|
||||||
|
val xcFrameworkTask = registerPodXCFrameworkTask(project, cocoapodsExtension, buildType)
|
||||||
|
registerPodPublishFatFrameworkTasks(project, xcFrameworkTask, buildType)
|
||||||
|
registerPodspecPublishTask(project, cocoapodsExtension, xcFrameworkTask, buildType)
|
||||||
|
xcFrameworkTask
|
||||||
|
}
|
||||||
|
|
||||||
|
project.registerTask("podPublishXCFramework", DefaultTask::class.java) { task ->
|
||||||
|
task.description = "Produces Release and Debug XCFrameworks with respective podspecs"
|
||||||
|
task.dependsOn(xcFrameworkTasks)
|
||||||
|
task.group = TASK_GROUP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun apply(project: Project): Unit = with(project) {
|
override fun apply(project: Project): Unit = with(project) {
|
||||||
|
|
||||||
@@ -568,6 +681,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||||
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||||
registerPodImportTask(project, kotlinExtension)
|
registerPodImportTask(project, kotlinExtension)
|
||||||
|
registerPodPublishTasks(project, cocoapodsExtension)
|
||||||
|
|
||||||
if (HostManager.hostIsMac && !isAvailableToProduceSynthetic) {
|
if (HostManager.hostIsMac && !isAvailableToProduceSynthetic) {
|
||||||
logger.quiet(
|
logger.quiet(
|
||||||
|
|||||||
+75
-39
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.COCOAPODS_EXTENSION_NAME
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.COCOAPODS_EXTENSION_NAME
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.GENERATE_WRAPPER_PROPERTY
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.GENERATE_WRAPPER_PROPERTY
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.SYNC_TASK_NAME
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.SYNC_TASK_NAME
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -31,11 +30,14 @@ import java.io.File
|
|||||||
open class PodspecTask : DefaultTask() {
|
open class PodspecTask : DefaultTask() {
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal val specName = project.name.asValidFrameworkName()
|
internal val specName = project.objects.property(String::class.java)
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
|
internal val outputDir = project.objects.property(File::class.java)
|
||||||
|
|
||||||
@get:OutputFile
|
@get:OutputFile
|
||||||
internal val outputFileProvider: Provider<File>
|
val outputFile: File
|
||||||
get() = project.provider { project.file("$specName.podspec") }
|
get() = outputDir.get().resolve("${specName.get()}.podspec")
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal lateinit var needPodspec: Provider<Boolean>
|
internal lateinit var needPodspec: Provider<Boolean>
|
||||||
@@ -44,7 +46,14 @@ open class PodspecTask : DefaultTask() {
|
|||||||
val pods = project.objects.listProperty(CocoapodsDependency::class.java)
|
val pods = project.objects.listProperty(CocoapodsDependency::class.java)
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal lateinit var version: Provider<String>
|
internal val version = project.objects.property(String::class.java)
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
internal val publishing = project.objects.property(Boolean::class.java)
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
@get:Optional
|
||||||
|
internal val source = project.objects.property(String::class.java)
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
@get:Optional
|
@get:Optional
|
||||||
@@ -62,6 +71,10 @@ open class PodspecTask : DefaultTask() {
|
|||||||
@get:Optional
|
@get:Optional
|
||||||
internal val summary = project.objects.property(String::class.java)
|
internal val summary = project.objects.property(String::class.java)
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
@get:Optional
|
||||||
|
internal val extraSpecAttributes = project.objects.mapProperty(String::class.java, String::class.java)
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal lateinit var frameworkName: Provider<String>
|
internal lateinit var frameworkName: Provider<String>
|
||||||
|
|
||||||
@@ -84,11 +97,14 @@ open class PodspecTask : DefaultTask() {
|
|||||||
@TaskAction
|
@TaskAction
|
||||||
fun generate() {
|
fun generate() {
|
||||||
|
|
||||||
val frameworkDir = project.cocoapodsBuildDirs.framework.relativeTo(outputFileProvider.get().parentFile).path
|
check(version.get() != Project.DEFAULT_VERSION) {
|
||||||
val dependencies = pods.get().map { pod ->
|
"""
|
||||||
val versionSuffix = if (pod.version != null) ", '${pod.version}'" else ""
|
Cocoapods Integration requires pod version to be specified.
|
||||||
"| spec.dependency '${pod.name}'$versionSuffix"
|
Please specify pod version by adding 'version = "<version>"' to the cocoapods block.
|
||||||
}.joinToString(separator = "\n")
|
Alternatively, specify the version for the entire project explicitly.
|
||||||
|
Pod version format has to conform podspec syntax requirements: https://guides.cocoapods.org/syntax/podspec.html#version
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
val gradleWrapper = (project.rootProject.tasks.getByName("wrapper") as? Wrapper)?.scriptFile
|
val gradleWrapper = (project.rootProject.tasks.getByName("wrapper") as? Wrapper)?.scriptFile
|
||||||
require(gradleWrapper != null && gradleWrapper.exists()) {
|
require(gradleWrapper != null && gradleWrapper.exists()) {
|
||||||
@@ -101,42 +117,37 @@ open class PodspecTask : DefaultTask() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
val gradleCommand = "\$REPO_ROOT/${gradleWrapper.toRelativeString(project.projectDir)}"
|
|
||||||
|
|
||||||
val deploymentTargets = run {
|
val deploymentTargets = run {
|
||||||
listOf(ios, osx, tvos, watchos).map { it.get() }.filter { it.deploymentTarget != null }.joinToString("\n") {
|
listOf(ios, osx, tvos, watchos).map { it.get() }.filter { it.deploymentTarget != null }.joinToString("\n") {
|
||||||
"| spec.${it.name}.deployment_target = '${it.deploymentTarget}'"
|
if (extraSpecAttributes.get().containsKey("${it.name}.deployment_target")) "" else "| spec.${it.name}.deployment_target = '${it.deploymentTarget}'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(outputFileProvider.get()) {
|
val dependencies = pods.get().map { pod ->
|
||||||
writeText(
|
val versionSuffix = if (pod.version != null) ", '${pod.version}'" else ""
|
||||||
"""
|
"| spec.dependency '${pod.name}'$versionSuffix"
|
||||||
|Pod::Spec.new do |spec|
|
}.joinToString(separator = "\n")
|
||||||
| spec.name = '$specName'
|
|
||||||
| spec.version = '${version.get()}'
|
val frameworkDir = project.cocoapodsBuildDirs.framework.relativeTo(outputFile.parentFile).path
|
||||||
| spec.homepage = '${homepage.getOrEmpty()}'
|
val vendoredFramework = if (publishing.get()) "${frameworkName.get()}.xcframework" else "$frameworkDir/${frameworkName.get()}.framework"
|
||||||
| spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
val vendoredFrameworks = if (extraSpecAttributes.get().containsKey("vendored_frameworks")) "" else "| spec.vendored_frameworks = '$vendoredFramework'"
|
||||||
| spec.authors = '${authors.getOrEmpty()}'
|
|
||||||
| spec.license = '${license.getOrEmpty()}'
|
val libraries = if (extraSpecAttributes.get().containsKey("libraries")) "" else "| spec.libraries = 'c++'"
|
||||||
| spec.summary = '${summary.getOrEmpty()}'
|
|
||||||
|
|
val xcConfig = if (publishing.get() || extraSpecAttributes.get().containsKey("pod_target_xcconfig")) "" else
|
||||||
| spec.vendored_frameworks = "$frameworkDir/${frameworkName.get()}.framework"
|
""" |
|
||||||
| spec.libraries = "c++"
|
|
||||||
| spec.module_name = "#{spec.name}_umbrella"
|
|
||||||
|
|
|
||||||
$deploymentTargets
|
|
||||||
|
|
|
||||||
$dependencies
|
|
||||||
|
|
|
||||||
| spec.pod_target_xcconfig = {
|
| spec.pod_target_xcconfig = {
|
||||||
| 'KOTLIN_PROJECT_PATH' => '${project.path}',
|
| 'KOTLIN_PROJECT_PATH' => '${project.path}',
|
||||||
| 'PRODUCT_MODULE_NAME' => '$specName',
|
| 'PRODUCT_MODULE_NAME' => '${frameworkName.get()}',
|
||||||
| }
|
| }
|
||||||
|
|
""".trimMargin()
|
||||||
|
|
||||||
|
val gradleCommand = "\$REPO_ROOT/${gradleWrapper.toRelativeString(project.projectDir)}"
|
||||||
|
val scriptPhase = if (publishing.get() || extraSpecAttributes.get().containsKey("script_phases")) "" else
|
||||||
|
""" |
|
||||||
| spec.script_phases = [
|
| spec.script_phases = [
|
||||||
| {
|
| {
|
||||||
| :name => 'Build $specName',
|
| :name => 'Build ${specName.get()}',
|
||||||
| :execution_position => :before_compile,
|
| :execution_position => :before_compile,
|
||||||
| :shell_path => '/bin/sh',
|
| :shell_path => '/bin/sh',
|
||||||
| :script => <<-SCRIPT
|
| :script => <<-SCRIPT
|
||||||
@@ -153,17 +164,39 @@ open class PodspecTask : DefaultTask() {
|
|||||||
| SCRIPT
|
| SCRIPT
|
||||||
| }
|
| }
|
||||||
| ]
|
| ]
|
||||||
|
""".trimMargin()
|
||||||
|
|
||||||
|
val customSpec = extraSpecAttributes.get().map { "| spec.${it.key} = ${it.value}" }.joinToString("\n")
|
||||||
|
|
||||||
|
with(outputFile) {
|
||||||
|
writeText(
|
||||||
|
"""
|
||||||
|
|Pod::Spec.new do |spec|
|
||||||
|
| spec.name = '${specName.get()}'
|
||||||
|
| spec.version = '${version.get()}'
|
||||||
|
| spec.homepage = ${homepage.getOrEmpty().surroundWithSingleQuotesIfNeeded()}
|
||||||
|
| spec.source = ${source.getOrElse("{ :http=> ''}")}
|
||||||
|
| spec.authors = ${authors.getOrEmpty().surroundWithSingleQuotesIfNeeded()}
|
||||||
|
| spec.license = ${license.getOrEmpty().surroundWithSingleQuotesIfNeeded()}
|
||||||
|
| spec.summary = '${summary.getOrEmpty()}'
|
||||||
|
$vendoredFrameworks
|
||||||
|
$libraries
|
||||||
|
$deploymentTargets
|
||||||
|
$dependencies
|
||||||
|
$xcConfig
|
||||||
|
$scriptPhase
|
||||||
|
$customSpec
|
||||||
|end
|
|end
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
)
|
)
|
||||||
|
|
||||||
if (hasPodfileOwnOrParent(project)) {
|
if (hasPodfileOwnOrParent(project) && publishing.get().not()) {
|
||||||
logger.quiet(
|
logger.quiet(
|
||||||
"""
|
"""
|
||||||
Generated a podspec file at: ${absolutePath}.
|
Generated a podspec file at: ${absolutePath}.
|
||||||
To include it in your Xcode project, check that the following dependency snippet exists in your Podfile:
|
To include it in your Xcode project, check that the following dependency snippet exists in your Podfile:
|
||||||
|
|
||||||
pod '$specName', :path => '${parentFile.absolutePath}'
|
pod '${specName.get()}', :path => '${parentFile.absolutePath}'
|
||||||
|
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
@@ -172,7 +205,10 @@ open class PodspecTask : DefaultTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Provider<String>.getOrEmpty() = getOrElse("")
|
private fun Provider<String>.getOrEmpty(): String = getOrElse("")
|
||||||
|
|
||||||
|
private fun String.surroundWithSingleQuotesIfNeeded(): String =
|
||||||
|
if (startsWith("{") || startsWith("<<-") || startsWith("'")) this else "'$this'"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val KotlinMultiplatformExtension?.cocoapodsExtensionOrNull: CocoapodsExtension?
|
private val KotlinMultiplatformExtension?.cocoapodsExtensionOrNull: CocoapodsExtension?
|
||||||
|
|||||||
+3
-2
@@ -82,7 +82,7 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
var baseName: String = project.name
|
var baseName: String = project.name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A parent directory for the fat framework..
|
* A parent directory for the fat framework.
|
||||||
*/
|
*/
|
||||||
@OutputDirectory
|
@OutputDirectory
|
||||||
var destinationDir: File = project.buildDir.resolve("fat-framework")
|
var destinationDir: File = project.buildDir.resolve("fat-framework")
|
||||||
@@ -98,7 +98,8 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
|
|
||||||
private val archToFramework: MutableMap<Architecture, Framework> = mutableMapOf()
|
private val archToFramework: MutableMap<Architecture, Framework> = mutableMapOf()
|
||||||
|
|
||||||
private val fatFrameworkName: String
|
@get:Internal
|
||||||
|
val fatFrameworkName: String
|
||||||
get() = baseName.asValidFrameworkName()
|
get() = baseName.asValidFrameworkName()
|
||||||
|
|
||||||
private val fatFramework: IosFrameworkFiles
|
private val fatFramework: IosFrameworkFiles
|
||||||
|
|||||||
Reference in New Issue
Block a user