[Gradle, CocoaPods] Improved CocoaPods Integration features with tests
This commit is contained in:
+5
-1
@@ -11,6 +11,11 @@ import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
|
||||
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||
|
||||
class KotlinCocoaPodsModelResolver : AbstractProjectResolverExtension() {
|
||||
override fun requiresTaskRunning(): Boolean = true
|
||||
|
||||
override fun getToolingExtensionsClasses(): Set<Class<out Any>> {
|
||||
return setOf(EnablePodImportTask::class.java)
|
||||
}
|
||||
|
||||
override fun getProjectsLoadedModelProvider(): ProjectImportModelProvider {
|
||||
return ClassSetProjectImportModelProvider(
|
||||
@@ -18,7 +23,6 @@ class KotlinCocoaPodsModelResolver : AbstractProjectResolverExtension() {
|
||||
)
|
||||
}
|
||||
|
||||
override fun requiresTaskRunning(): Boolean = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ class KotlinCocoaPodsModelBuilder : AbstractModelBuilderService() {
|
||||
|
||||
override fun buildAll(modelName: String, project: Project, context: ModelBuilderContext): Any? {
|
||||
val startParameter = project.gradle.startParameter
|
||||
val taskNames = startParameter.taskNames
|
||||
val taskNames = mutableListOf<String>()
|
||||
taskNames.addAll(startParameter.taskNames)
|
||||
|
||||
if (project.tasks.findByPath(POD_IMPORT_TASK_NAME) != null && POD_IMPORT_TASK_NAME !in taskNames) {
|
||||
taskNames.add(POD_IMPORT_TASK_NAME)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.commonizer.KotlinCommonizerModelResolver" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleCoroutineDebugProjectResolver" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.commonizer.KotlinCommonizerModelResolver" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.cocoapods.KotlinCocoaPodsModelResolver" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleCoroutineDebugProjectResolver" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
|
||||
|
||||
+24
@@ -479,6 +479,12 @@ abstract class BaseGradleIT {
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.assertTasksExecutedByPrefix(taskPrefixes: Iterable<String>) {
|
||||
for (prefix in taskPrefixes) {
|
||||
assertContainsRegex("(Executing actions for task|Executing task) '$prefix\\w*'".toRegex())
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.assertTasksExecuted(vararg tasks: String) {
|
||||
assertTasksExecuted(tasks.toList())
|
||||
}
|
||||
@@ -521,6 +527,18 @@ abstract class BaseGradleIT {
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.assertTasksRegisteredByPrefix(taskPrefixes: Iterable<String>) {
|
||||
for (prefix in taskPrefixes) {
|
||||
assertContainsRegex("'Register task $prefix\\w*'".toRegex())
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.assertTasksNotRegisteredByPrefix(taskPrefixes: Iterable<String>) {
|
||||
for (prefix in taskPrefixes) {
|
||||
assertNotContains("'Register task $prefix\\w*'".toRegex())
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.assertTasksNotRealized(vararg tasks: String) {
|
||||
for (task in tasks) {
|
||||
assertNotContains("'Realize task $task'")
|
||||
@@ -538,6 +556,12 @@ abstract class BaseGradleIT {
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.assertTasksSkippedByPrefix(taskPrefixes: Iterable<String>) {
|
||||
for (prefix in taskPrefixes) {
|
||||
assertContainsRegex("Skipping task '$prefix\\w*'".toRegex())
|
||||
}
|
||||
}
|
||||
|
||||
fun CompiledProject.getOutputForTask(taskName: String): String {
|
||||
@Language("RegExp")
|
||||
val taskOutputRegex = """
|
||||
|
||||
+348
-140
@@ -5,6 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_BUILD_DEPENDENCIES_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_GEN_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_SETUP_BUILD_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.junit.Assume.assumeTrue
|
||||
@@ -19,124 +23,241 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
override val defaultGradleVersion: GradleVersionRequired
|
||||
get() = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||
|
||||
|
||||
// We use Kotlin DSL. Earlier Gradle versions fail at accessors codegen.
|
||||
val gradleVersion = GradleVersionRequired.None
|
||||
val gradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||
|
||||
val PODFILE_IMPORT_DIRECTIVE_PLACEHOLDER = "<import_mode_directive>"
|
||||
|
||||
@Test
|
||||
fun testPodspec() = doTestPodspec()
|
||||
val cocoapodsSingleKtPod = "new-mpp-cocoapods-single"
|
||||
val cocoapodsMultipleKtPods = "new-mpp-cocoapods-multiple"
|
||||
|
||||
@Test
|
||||
fun testPodspecCustomFrameworkName() = doTestPodspec("MultiPlatformLibrary")
|
||||
fun testPodspecSingle() = doTestPodspec(
|
||||
cocoapodsSingleKtPod,
|
||||
mapOf("kotlin-library" to null),
|
||||
mapOf("kotlin-library" to kotlinLibraryPodspecContent())
|
||||
)
|
||||
|
||||
private fun doTestPodspec(frameworkName: String? = null) {
|
||||
@Test
|
||||
fun testPodspecCustomFrameworkNameSingle() = doTestPodspec(
|
||||
cocoapodsSingleKtPod,
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary"),
|
||||
mapOf("kotlin-library" to kotlinLibraryPodspecContent("MultiplatformLibrary"))
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app", mapOf("kotlin-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksWithCustomFrameworkNameSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersWithCustomFrameworkNameSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPodImportUseFrameworksSingle() = doTestPodImport(
|
||||
cocoapodsSingleKtPod,
|
||||
"ios-app",
|
||||
ImportMode.FRAMEWORKS,
|
||||
listOf("kotlin-library")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPodImportUseModularHeadersSingle() =
|
||||
doTestPodImport(
|
||||
cocoapodsSingleKtPod,
|
||||
"ios-app",
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
listOf("kotlin-library")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPodspecMupltiple() = doTestPodspec(
|
||||
cocoapodsMultipleKtPods,
|
||||
mapOf("kotlin-library" to null, "second-library" to null),
|
||||
mapOf("kotlin-library" to kotlinLibraryPodspecContent(), "second-library" to secondLibraryPodspecContent()),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPodspecCustomFrameworkNameMupltiple() = doTestPodspec(
|
||||
cocoapodsMultipleKtPods,
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary"),
|
||||
mapOf(
|
||||
"kotlin-library" to kotlinLibraryPodspecContent("FirstMultiplatformLibrary"),
|
||||
"second-library" to secondLibraryPodspecContent("SecondMultiplatformLibrary")
|
||||
)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksMupltiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to null, "second-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksWithCustomFrameworkNameMupltiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersMupltiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to null, "second-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersWithCustomFrameworkNameMupltiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPodImportUseFrameworksMupltiple() = doTestPodImport(
|
||||
cocoapodsMultipleKtPods,
|
||||
"ios-app",
|
||||
ImportMode.FRAMEWORKS,
|
||||
listOf("kotlin-library", "second-library")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPodImportUseModularHeadersMupltiple() =
|
||||
doTestPodImport(
|
||||
cocoapodsMultipleKtPods,
|
||||
"ios-app",
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
listOf("kotlin-library", "second-library")
|
||||
)
|
||||
|
||||
private fun doTestPodspec(
|
||||
projectName: String,
|
||||
subprojectsToFrameworkNamesMap: Map<String, String?>,
|
||||
subprojectsToPodspecContentMap: Map<String, String?>
|
||||
) {
|
||||
assumeTrue(HostManager.hostIsMac)
|
||||
val gradleProject = transformProjectWithPluginsDsl("new-mpp-cocoapods", gradleVersion)
|
||||
val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion)
|
||||
|
||||
// Check that the podspec task fails if there is no Gradle wrapper in the project.
|
||||
gradleProject.build(":kotlin-library:podspec") {
|
||||
assertFailed()
|
||||
assertContains("The Gradle wrapper is required to run the build from Xcode.")
|
||||
assertContains(
|
||||
"Please run the same command with `-Pkotlin.native.cocoapods.generate.wrapper=true` " +
|
||||
"or run the `:wrapper` task to generate the wrapper manually."
|
||||
)
|
||||
gradleProject.build(":podspec") {
|
||||
assertSuccessful()
|
||||
assertTasksSkipped(":podspec")
|
||||
assertNoSuchFile("cocoapods.podspec")
|
||||
}
|
||||
|
||||
// Check that we can generate the wrapper along with the podspec if the corresponding property specified
|
||||
gradleProject.build(":kotlin-library:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
for ((subproject, frameworkName) in subprojectsToFrameworkNamesMap) {
|
||||
frameworkName?.also {
|
||||
gradleProject.gradleBuildScript(subproject).appendText(
|
||||
"""
|
||||
|kotlin {
|
||||
| cocoapods {
|
||||
| frameworkName = "$frameworkName"
|
||||
| }
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
// Check that we can generate the wrapper along with the podspec if the corresponding property specified
|
||||
gradleProject.build(":$subproject:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(":$subproject:podspec")
|
||||
|
||||
// Check that the podspec file is correctly generated.
|
||||
val podspecFileName = "$subproject/${subproject.validFrameworkName}.podspec"
|
||||
|
||||
|
||||
|
||||
assertFileExists(podspecFileName)
|
||||
val actualPodspecContentWithoutBlankLines = fileInWorkingDir(podspecFileName).readText()
|
||||
.lineSequence()
|
||||
.filter { it.isNotBlank() }
|
||||
.joinToString("\n")
|
||||
|
||||
assertEquals(subprojectsToPodspecContentMap[subproject], actualPodspecContentWithoutBlankLines)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doTestPodImport(
|
||||
projectName: String,
|
||||
iosAppLocation: String,
|
||||
mode: ImportMode,
|
||||
subprojects: List<String>
|
||||
) {
|
||||
assumeTrue(HostManager.hostIsMac)
|
||||
assumeTrue(KotlinCocoapodsPlugin.isAvailableToProduceSynthetic())
|
||||
|
||||
val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion)
|
||||
with(gradleProject) {
|
||||
preparePodfile(iosAppLocation, mode)
|
||||
podImportAsserts()
|
||||
subprojects.forEach { podImportAsserts(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun BaseGradleIT.Project.podImportAsserts(subproject: String? = null) {
|
||||
val buildScriptText = gradleBuildScript(subproject).readText()
|
||||
val taskPrefix = subproject?.let { ":$it" } ?: ""
|
||||
val podImport = "podImport"
|
||||
val podspec = "podspec"
|
||||
val podInstall = "podInstall"
|
||||
|
||||
build("$taskPrefix:$podImport", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(":kotlin-library:podspec", ":wrapper")
|
||||
assertFileExists("gradlew")
|
||||
|
||||
// Check that the podspec file is correctly generated.
|
||||
val podspecFileName = "kotlin-library/kotlin_library.podspec"
|
||||
if ("noPodspec()" in buildScriptText) {
|
||||
assertTasksSkipped("$taskPrefix:$podspec")
|
||||
}
|
||||
|
||||
if ("podfile" in buildScriptText) {
|
||||
assertTasksExecuted("$taskPrefix:$podInstall")
|
||||
} else {
|
||||
assertTasksSkipped("$taskPrefix:$podInstall")
|
||||
}
|
||||
assertTasksRegisteredByPrefix(listOf("$taskPrefix:$POD_GEN_TASK_NAME"))
|
||||
if (buildScriptText.matches("pod\\(.*\\)".toRegex())) {
|
||||
assertTasksExecutedByPrefix(listOf("$taskPrefix:$POD_GEN_TASK_NAME"))
|
||||
}
|
||||
|
||||
frameworkName?.let {
|
||||
fileInWorkingDir(podspecFileName).modify {
|
||||
it.replace("build/cocoapods/framework/kotlin_library.framework", "build/cocoapods/framework/$frameworkName.framework")
|
||||
with(listOf(POD_SETUP_BUILD_TASK_NAME, POD_BUILD_DEPENDENCIES_TASK_NAME).map { "$taskPrefix:$it" }) {
|
||||
if (buildScriptText.matches("pod\\(.*\\)".toRegex())) {
|
||||
assertTasksRegisteredByPrefix(this)
|
||||
assertTasksExecutedByPrefix(this)
|
||||
}
|
||||
}
|
||||
|
||||
val expectedPodspecContent = """
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'kotlin_library'
|
||||
spec.version = '1.0'
|
||||
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
||||
spec.authors = ''
|
||||
spec.license = ''
|
||||
spec.summary = 'CocoaPods test library'
|
||||
|
||||
spec.static_framework = true
|
||||
spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework"
|
||||
spec.libraries = "c++"
|
||||
spec.module_name = "#{spec.name}_umbrella"
|
||||
|
||||
spec.dependency 'pod_dependency', '1.0'
|
||||
spec.dependency 'subspec_dependency/Core', '1.0'
|
||||
|
||||
spec.pod_target_xcconfig = {
|
||||
'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64',
|
||||
'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm',
|
||||
'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x86',
|
||||
'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm',
|
||||
'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64',
|
||||
'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64',
|
||||
'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64'
|
||||
}
|
||||
|
||||
spec.script_phases = [
|
||||
{
|
||||
:name => 'Build kotlin_library',
|
||||
:execution_position => :before_compile,
|
||||
:shell_path => '/bin/sh',
|
||||
:script => <<-SCRIPT
|
||||
set -ev
|
||||
REPO_ROOT="${'$'}PODS_TARGET_SRCROOT"
|
||||
"${'$'}REPO_ROOT/../gradlew" -p "${'$'}REPO_ROOT" :kotlin-library:syncFramework \
|
||||
-Pkotlin.native.cocoapods.target=${'$'}KOTLIN_TARGET \
|
||||
-Pkotlin.native.cocoapods.configuration=${'$'}CONFIGURATION \
|
||||
-Pkotlin.native.cocoapods.cflags="${'$'}OTHER_CFLAGS" \
|
||||
-Pkotlin.native.cocoapods.paths.headers="${'$'}HEADER_SEARCH_PATHS" \
|
||||
-Pkotlin.native.cocoapods.paths.frameworks="${'$'}FRAMEWORK_SEARCH_PATHS"
|
||||
SCRIPT
|
||||
}
|
||||
]
|
||||
end
|
||||
""".trimIndent()
|
||||
|
||||
assertFileExists(podspecFileName)
|
||||
assertEquals(expectedPodspecContent, fileInWorkingDir(podspecFileName).readText())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInterop() {
|
||||
assumeTrue(HostManager.hostIsMac)
|
||||
val gradleProject = transformProjectWithPluginsDsl("new-mpp-cocoapods", gradleVersion)
|
||||
with(gradleProject) {
|
||||
// Check that a project with CocoaPods interop fails to be built from command line.
|
||||
build(":kotlin-library:build") {
|
||||
assertFailed()
|
||||
assertContains("Cannot perform cinterop processing for module pod_dependency: cannot determine headers location.")
|
||||
}
|
||||
|
||||
// Check that a project without CocoaPods interop can be built from command line.
|
||||
gradleBuildScript("kotlin-library").modify {
|
||||
it.replace("""pod("pod_dependency", "1.0")""", "").replace("""pod("subspec_dependency/Core", "1.0")""", "")
|
||||
}
|
||||
projectDir.resolve("kotlin-library/src/iosMain/kotlin/A.kt").modify {
|
||||
it.replace("import cocoapods.pod_dependency.*", "").replace("println(foo())", "")
|
||||
.replace("import cocoapods.subspec_dependency.*", "").replace("println(baz())", "")
|
||||
}
|
||||
build(":kotlin-library:linkReleaseFrameworkIOS") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class ImportMode(val directive: String) {
|
||||
FRAMEWORKS("use_frameworks!"),
|
||||
@@ -177,40 +298,47 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
CommandResult(process.exitValue(), stdOut, stdErr).block()
|
||||
}
|
||||
|
||||
private fun doTestXcode(mode: ImportMode, isCustomFrameworkName: Boolean) {
|
||||
private fun doTestXcode(
|
||||
projectName: String,
|
||||
mode: ImportMode,
|
||||
iosAppLocation: String,
|
||||
subprojectsToFrameworkNamesMap: Map<String, String?>
|
||||
) {
|
||||
assumeTrue(HostManager.hostIsMac)
|
||||
val gradleProject = transformProjectWithPluginsDsl("new-mpp-cocoapods", gradleVersion)
|
||||
val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion)
|
||||
|
||||
with(gradleProject) {
|
||||
setupWorkingDir()
|
||||
|
||||
// Add property with custom framework name
|
||||
if (isCustomFrameworkName) {
|
||||
gradleBuildScript("kotlin-library").appendText(
|
||||
"""
|
||||
kotlin {
|
||||
cocoapods {
|
||||
frameworkName = "MultiPlatformLibrary"
|
||||
for ((subproject, frameworkName) in subprojectsToFrameworkNamesMap) {
|
||||
|
||||
// Add property with custom framework name
|
||||
frameworkName?.also { name ->
|
||||
gradleBuildScript(subproject).appendText(
|
||||
"""
|
||||
kotlin {
|
||||
cocoapods {
|
||||
frameworkName = "$name"
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// Change swift sources import
|
||||
val iosAppDir = projectDir.resolve(iosAppLocation)
|
||||
iosAppDir.resolve("ios-app/ViewController.swift").modify {
|
||||
it.replace("import ${subproject.validFrameworkName}", "import $name")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// Change swift sources import
|
||||
val iosAppDir = projectDir.resolve("ios-app")
|
||||
iosAppDir.resolve("ios-app/ViewController.swift").modify {
|
||||
it.replace("import kotlin_library", "import MultiPlatformLibrary")
|
||||
|
||||
// Generate podspec.
|
||||
gradleProject.build(":$subproject:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Generate podspec.
|
||||
gradleProject.build(":kotlin-library:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
val iosAppDir = projectDir.resolve("ios-app")
|
||||
val iosAppDir = projectDir.resolve(iosAppLocation)
|
||||
|
||||
// Set import mode for Podfile.
|
||||
iosAppDir.resolve("Podfile").modify {
|
||||
@@ -218,17 +346,8 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
|
||||
// Install pods.
|
||||
runCommand(iosAppDir, "pod", "install") {
|
||||
assertEquals(
|
||||
0, exitCode, """
|
||||
|Exit code mismatch for `pod install`.
|
||||
|stdout:
|
||||
|$stdOut
|
||||
|
|
||||
|stderr:
|
||||
|$stdErr
|
||||
""".trimMargin()
|
||||
)
|
||||
gradleProject.build(":podInstall", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
// Run Xcode build.
|
||||
@@ -237,8 +356,8 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
"-sdk", "iphonesimulator",
|
||||
"-arch", "arm64",
|
||||
"-configuration", "Release",
|
||||
"-workspace", "ios-app.xcworkspace",
|
||||
"-scheme", "ios-app",
|
||||
"-workspace", "${iosAppDir.name}.xcworkspace",
|
||||
"-scheme", iosAppDir.name,
|
||||
inheritIO = true // Xcode doesn't finish the process if the PIPE redirect is used.
|
||||
) {
|
||||
assertEquals(
|
||||
@@ -255,13 +374,102 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworks() = doTestXcode(ImportMode.FRAMEWORKS, false)
|
||||
private fun Project.preparePodfile(iosAppLocation: String, mode: ImportMode) {
|
||||
val iosAppDir = projectDir.resolve(iosAppLocation)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeaders() = doTestXcode(ImportMode.MODULAR_HEADERS, false)
|
||||
// Set import mode for Podfile.
|
||||
iosAppDir.resolve("Podfile").modify {
|
||||
it.replace(PODFILE_IMPORT_DIRECTIVE_PLACEHOLDER, mode.directive)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testXcodeWithCustomFrameworkName() = doTestXcode(ImportMode.FRAMEWORKS, true)
|
||||
private val String.validFrameworkName: String
|
||||
get() = replace('-', '_')
|
||||
|
||||
private fun kotlinLibraryPodspecContent(frameworkName: String? = null) = """
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'kotlin_library'
|
||||
spec.version = '1.0'
|
||||
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
||||
spec.authors = ''
|
||||
spec.license = ''
|
||||
spec.summary = 'CocoaPods test library'
|
||||
spec.static_framework = true
|
||||
spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework"
|
||||
spec.libraries = "c++"
|
||||
spec.module_name = "#{spec.name}_umbrella"
|
||||
spec.dependency 'pod_dependency', '1.0'
|
||||
spec.dependency 'subspec_dependency/Core', '1.0'
|
||||
spec.pod_target_xcconfig = {
|
||||
'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64',
|
||||
'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm',
|
||||
'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x86',
|
||||
'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm',
|
||||
'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64',
|
||||
'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64',
|
||||
'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64'
|
||||
}
|
||||
spec.script_phases = [
|
||||
{
|
||||
:name => 'Build kotlin_library',
|
||||
:execution_position => :before_compile,
|
||||
:shell_path => '/bin/sh',
|
||||
:script => <<-SCRIPT
|
||||
set -ev
|
||||
REPO_ROOT="${'$'}PODS_TARGET_SRCROOT"
|
||||
"${'$'}REPO_ROOT/../gradlew" -p "${'$'}REPO_ROOT" :kotlin-library:syncFramework \
|
||||
-Pkotlin.native.cocoapods.target=${'$'}KOTLIN_TARGET \
|
||||
-Pkotlin.native.cocoapods.configuration=${'$'}CONFIGURATION \
|
||||
-Pkotlin.native.cocoapods.cflags="${'$'}OTHER_CFLAGS" \
|
||||
-Pkotlin.native.cocoapods.paths.headers="${'$'}HEADER_SEARCH_PATHS" \
|
||||
-Pkotlin.native.cocoapods.paths.frameworks="${'$'}FRAMEWORK_SEARCH_PATHS"
|
||||
SCRIPT
|
||||
}
|
||||
]
|
||||
end
|
||||
""".trimIndent()
|
||||
|
||||
private fun secondLibraryPodspecContent(frameworkName: String? = null) = """
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'second_library'
|
||||
spec.version = '1.0'
|
||||
spec.homepage = 'https://github.com/JetBrains/kotlin'
|
||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
||||
spec.authors = ''
|
||||
spec.license = ''
|
||||
spec.summary = 'CocoaPods test library'
|
||||
spec.static_framework = true
|
||||
spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "second_library"}.framework"
|
||||
spec.libraries = "c++"
|
||||
spec.module_name = "#{spec.name}_umbrella"
|
||||
spec.pod_target_xcconfig = {
|
||||
'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64',
|
||||
'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm',
|
||||
'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x86',
|
||||
'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm',
|
||||
'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64',
|
||||
'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64',
|
||||
'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64'
|
||||
}
|
||||
spec.script_phases = [
|
||||
{
|
||||
:name => 'Build second_library',
|
||||
:execution_position => :before_compile,
|
||||
:shell_path => '/bin/sh',
|
||||
:script => <<-SCRIPT
|
||||
set -ev
|
||||
REPO_ROOT="${'$'}PODS_TARGET_SRCROOT"
|
||||
"${'$'}REPO_ROOT/../gradlew" -p "${'$'}REPO_ROOT" :second-library:syncFramework \
|
||||
-Pkotlin.native.cocoapods.target=${'$'}KOTLIN_TARGET \
|
||||
-Pkotlin.native.cocoapods.configuration=${'$'}CONFIGURATION \
|
||||
-Pkotlin.native.cocoapods.cflags="${'$'}OTHER_CFLAGS" \
|
||||
-Pkotlin.native.cocoapods.paths.headers="${'$'}HEADER_SEARCH_PATHS" \
|
||||
-Pkotlin.native.cocoapods.paths.frameworks="${'$'}FRAMEWORK_SEARCH_PATHS"
|
||||
SCRIPT
|
||||
}
|
||||
]
|
||||
end
|
||||
""".trimIndent()
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
ios-app/Pods
|
||||
Podfile.lock
|
||||
kotlin-library/kotlin_library.podspec
|
||||
second-library/second_library.podspec
|
||||
ios-app/ios-app.xcodeproj/xcuserdata
|
||||
ios-app/ios-app.xcworkspace/xcuserdata
|
||||
ios-app/ios-app.xcodeproj/project.xcworkspace/xcuserdata
|
||||
ios-app/ios-app.xcworkspace/contents.xcworkspacedata
|
||||
ios-app/ios-app.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
|
||||
+2
-4
@@ -19,9 +19,7 @@ kotlin {
|
||||
iosX64("iOS")
|
||||
|
||||
cocoapods {
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
pod("pod_dependency", "1.0")
|
||||
pod("subspec_dependency/Core", "1.0")
|
||||
noPodspec()
|
||||
podfile = projectDir.resolve("ios-app/Podfile")
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<import_mode_directive>
|
||||
|
||||
platform :ios, '9.0'
|
||||
|
||||
target 'ios-app' do
|
||||
pod 'pod_dependency', :path => '../pod_dependency'
|
||||
pod 'subspec_dependency', :path => '../subspec_dependency'
|
||||
pod 'kotlin_library', :path => '../kotlin-library'
|
||||
pod 'second_library', :path => '../second-library'
|
||||
end
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import UIKit
|
||||
import kotlin_library
|
||||
import second_library
|
||||
|
||||
class ViewController: UIViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
AKt.bar()
|
||||
AKt.bazz()
|
||||
BKt.secondBar()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
plugins {
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
id("org.jetbrains.kotlin.native.cocoapods")
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "1.0"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") }
|
||||
}
|
||||
|
||||
group = "org.jetbrains.kotlin.sample.native"
|
||||
version = "1.0"
|
||||
|
||||
kotlin {
|
||||
iosX64("iOS")
|
||||
|
||||
cocoapods {
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
pod("pod_dependency", "1.0", projectDir.resolve("../pod_dependency/pod_dependency.podspec"))
|
||||
pod("subspec_dependency/Core", "1.0", projectDir.resolve("../subspec_dependency/subspec_dependency.podspec"))
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
kotlin.native.disableCompilerDaemon=true
|
||||
kotlin.native.cacheKind=none
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
id("org.jetbrains.kotlin.native.cocoapods")
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "1.0"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") }
|
||||
}
|
||||
|
||||
group = "org.jetbrains.kotlin.sample.native"
|
||||
version = "1.0"
|
||||
|
||||
kotlin {
|
||||
iosX64("iOS")
|
||||
|
||||
cocoapods {
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
kotlin.native.disableCompilerDaemon=true
|
||||
kotlin.native.cacheKind=none
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun secondBar() {}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
enableFeaturePreview('GRADLE_METADATA')
|
||||
|
||||
// We move the actual library in a subproject to test accessing gradle wrapper from Xcode.
|
||||
rootProject.name = "cocoapods"
|
||||
include 'kotlin-library'
|
||||
include 'second-library'
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
id("org.jetbrains.kotlin.multiplatform").version("<pluginMarkerVersion>")
|
||||
id("org.jetbrains.kotlin.native.cocoapods").version("<pluginMarkerVersion>")
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "1.0"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") }
|
||||
}
|
||||
|
||||
group = "org.jetbrains.kotlin.sample.native"
|
||||
version = "1.0"
|
||||
|
||||
kotlin {
|
||||
iosX64("iOS")
|
||||
|
||||
cocoapods {
|
||||
noPodspec()
|
||||
podfile = projectDir.resolve("ios-app/Podfile")
|
||||
}
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2C4835762268863D00C928E6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C4835752268863D00C928E6 /* AppDelegate.swift */; };
|
||||
2C4835782268863D00C928E6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C4835772268863D00C928E6 /* ViewController.swift */; };
|
||||
2C48357B2268863D00C928E6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C4835792268863D00C928E6 /* Main.storyboard */; };
|
||||
2C48357D2268863E00C928E6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C48357C2268863E00C928E6 /* Assets.xcassets */; };
|
||||
2C4835802268863E00C928E6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C48357E2268863E00C928E6 /* LaunchScreen.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2C4835722268863D00C928E6 /* ios-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ios-app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2C4835752268863D00C928E6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
2C4835772268863D00C928E6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
2C48357A2268863D00C928E6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
2C48357C2268863E00C928E6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
2C48357F2268863E00C928E6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
2C4835812268863E00C928E6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
2C48356F2268863D00C928E6 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
2C4835692268863D00C928E6 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2C4835742268863D00C928E6 /* ios-app */,
|
||||
2C4835732268863D00C928E6 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2C4835732268863D00C928E6 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2C4835722268863D00C928E6 /* ios-app.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2C4835742268863D00C928E6 /* ios-app */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2C4835752268863D00C928E6 /* AppDelegate.swift */,
|
||||
2C4835772268863D00C928E6 /* ViewController.swift */,
|
||||
2C4835792268863D00C928E6 /* Main.storyboard */,
|
||||
2C48357C2268863E00C928E6 /* Assets.xcassets */,
|
||||
2C48357E2268863E00C928E6 /* LaunchScreen.storyboard */,
|
||||
2C4835812268863E00C928E6 /* Info.plist */,
|
||||
);
|
||||
path = "ios-app";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
2C4835712268863D00C928E6 /* ios-app */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 2C4835842268863E00C928E6 /* Build configuration list for PBXNativeTarget "ios-app" */;
|
||||
buildPhases = (
|
||||
2C48356E2268863D00C928E6 /* Sources */,
|
||||
2C48356F2268863D00C928E6 /* Frameworks */,
|
||||
2C4835702268863D00C928E6 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "ios-app";
|
||||
productName = "ios-app";
|
||||
productReference = 2C4835722268863D00C928E6 /* ios-app.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
2C48356A2268863D00C928E6 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1020;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = jetbrains;
|
||||
TargetAttributes = {
|
||||
2C4835712268863D00C928E6 = {
|
||||
CreatedOnToolsVersion = 10.2;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 2C48356D2268863D00C928E6 /* Build configuration list for PBXProject "ios-app" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 2C4835692268863D00C928E6;
|
||||
productRefGroup = 2C4835732268863D00C928E6 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
2C4835712268863D00C928E6 /* ios-app */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
2C4835702268863D00C928E6 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2C4835802268863E00C928E6 /* LaunchScreen.storyboard in Resources */,
|
||||
2C48357D2268863E00C928E6 /* Assets.xcassets in Resources */,
|
||||
2C48357B2268863D00C928E6 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
2C48356E2268863D00C928E6 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2C4835782268863D00C928E6 /* ViewController.swift in Sources */,
|
||||
2C4835762268863D00C928E6 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
2C4835792268863D00C928E6 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
2C48357A2268863D00C928E6 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2C48357E2268863E00C928E6 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
2C48357F2268863E00C928E6 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
2C4835822268863E00C928E6 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2C4835832268863E00C928E6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2C4835852268863E00C928E6 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "ios-app/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.konan.ios-app";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2C4835862268863E00C928E6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "ios-app/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.konan.ios-app";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
2C48356D2268863D00C928E6 /* Build configuration list for PBXProject "ios-app" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2C4835822268863E00C928E6 /* Debug */,
|
||||
2C4835832268863E00C928E6 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2C4835842268863E00C928E6 /* Build configuration list for PBXNativeTarget "ios-app" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2C4835852268863E00C928E6 /* Debug */,
|
||||
2C4835862268863E00C928E6 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 2C48356A2268863D00C928E6 /* Project object */;
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "20x20",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "20x20",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "29x29",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "29x29",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "40x40",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "40x40",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "60x60",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "60x60",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "20x20",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "20x20",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "29x29",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "29x29",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "40x40",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "40x40",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "76x76",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "76x76",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "ipad",
|
||||
"size": "83.5x83.5",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "ios-marketing",
|
||||
"size": "1024x1024",
|
||||
"scale": "1x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
plugins {
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
id("org.jetbrains.kotlin.native.cocoapods")
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "1.0"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") }
|
||||
}
|
||||
|
||||
group = "org.jetbrains.kotlin.sample.native"
|
||||
version = "1.0"
|
||||
|
||||
kotlin {
|
||||
iosX64("iOS")
|
||||
|
||||
cocoapods {
|
||||
summary = "CocoaPods test library"
|
||||
homepage = "https://github.com/JetBrains/kotlin"
|
||||
pod("pod_dependency", "1.0", projectDir.resolve("../pod_dependency/pod_dependency.podspec"))
|
||||
pod("subspec_dependency/Core", "1.0", projectDir.resolve("../subspec_dependency/subspec_dependency.podspec"))
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import cocoapods.pod_dependency.*
|
||||
import cocoapods.subspec_dependency.*
|
||||
|
||||
fun bar() {
|
||||
println(foo())
|
||||
}
|
||||
|
||||
fun bazz() {
|
||||
println(baz())
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'pod_dependency'
|
||||
spec.version = '1.0'
|
||||
spec.homepage = 'foo'
|
||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
||||
spec.authors = ''
|
||||
spec.license = ''
|
||||
spec.summary = 'foo'
|
||||
spec.source_files = 'src/*'
|
||||
spec.public_header_files = 'src/*.h'
|
||||
end
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NSString* foo(void);
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
#include "foo.h"
|
||||
|
||||
NSString* foo() {
|
||||
return @"Foo";
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NSString* baz(void);
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
#include "baz.h"
|
||||
|
||||
NSString* baz() {
|
||||
return @"Baz";
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'subspec_dependency'
|
||||
spec.version = '1.0'
|
||||
spec.homepage = 'baz'
|
||||
spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
|
||||
spec.authors = ''
|
||||
spec.license = ''
|
||||
spec.summary = 'baz'
|
||||
spec.default_subspec = 'Core'
|
||||
|
||||
spec.subspec 'Core' do |core|
|
||||
core.source_files = "src/*"
|
||||
core.public_header_files = "src/*.h"
|
||||
end
|
||||
end
|
||||
+41
-13
@@ -17,17 +17,6 @@ open class CocoapodsExtension(private val project: Project) {
|
||||
val version: String
|
||||
get() = project.version.toString()
|
||||
|
||||
@Optional
|
||||
@InputFile
|
||||
var podfile: File? = null
|
||||
|
||||
/**
|
||||
* Configure path to the Podfile.
|
||||
*/
|
||||
fun podfile(path: String) {
|
||||
podfile = project.file(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure authors of the pod built from this project.
|
||||
*/
|
||||
@@ -35,6 +24,23 @@ open class CocoapodsExtension(private val project: Project) {
|
||||
@Input
|
||||
var authors: String? = null
|
||||
|
||||
/**
|
||||
* Configure existing file `Podfile`.
|
||||
*/
|
||||
@Optional
|
||||
@InputFile
|
||||
var podfile: File? = null
|
||||
|
||||
@get:Input
|
||||
internal var needPodspec: Boolean = true
|
||||
|
||||
/**
|
||||
* Setup plugin not to produce podspec file for cocoapods section
|
||||
*/
|
||||
fun noPodspec() {
|
||||
needPodspec = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure license of the pod built from this project.
|
||||
*/
|
||||
@@ -56,6 +62,18 @@ open class CocoapodsExtension(private val project: Project) {
|
||||
@Input
|
||||
var homepage: String? = null
|
||||
|
||||
@Nested
|
||||
val ios: PodspecPlatformSettings = PodspecPlatformSettings("ios")
|
||||
|
||||
@Nested
|
||||
val osx: PodspecPlatformSettings = PodspecPlatformSettings("osx")
|
||||
|
||||
@Nested
|
||||
val tvos: PodspecPlatformSettings = PodspecPlatformSettings("tvos")
|
||||
|
||||
@Nested
|
||||
val watchos: PodspecPlatformSettings = PodspecPlatformSettings("watchos")
|
||||
|
||||
/**
|
||||
* Configure framework name of the pod built from this project.
|
||||
*/
|
||||
@@ -81,17 +99,27 @@ open class CocoapodsExtension(private val project: Project) {
|
||||
* Add a CocoaPods dependency to the pod built from this project.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun pod(name: String, version: String? = null, moduleName: String = name.split("/")[0]) {
|
||||
fun pod(name: String, version: String? = null, podspec: File? = null, moduleName: String = name.split("/")[0]) {
|
||||
check(_pods.findByName(name) == null) { "Project already has a CocoaPods dependency with name $name" }
|
||||
_pods.add(CocoapodsDependency(name, version, moduleName))
|
||||
_pods.add(CocoapodsDependency(name, version, podspec, moduleName))
|
||||
}
|
||||
|
||||
data class CocoapodsDependency(
|
||||
private val name: String,
|
||||
@get:Optional @get:Input val version: String?,
|
||||
@get:Optional @get:InputFile val podspec: File?,
|
||||
@get:Input val moduleName: String
|
||||
) : Named {
|
||||
@Input
|
||||
override fun getName(): String = name
|
||||
}
|
||||
|
||||
data class PodspecPlatformSettings(
|
||||
private val name: String,
|
||||
@get:Optional @get:Input var deploymentTarget: String? = null
|
||||
) : Named {
|
||||
|
||||
@Input
|
||||
override fun getName(): String = name
|
||||
}
|
||||
}
|
||||
+110
-40
@@ -12,23 +12,23 @@ import org.gradle.api.Task
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Sync
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.addExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildSettingsProperties
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildTask
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodInstallTask
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodSetupBuildTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.DefFileTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.DummyFrameworkTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.PodspecTask
|
||||
import org.jetbrains.kotlin.gradle.utils.asValidTaskName
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
internal val Project.cocoapodsBuildDirs: CocoapodsBuildDirs
|
||||
get() = CocoapodsBuildDirs(this)
|
||||
@@ -43,17 +43,35 @@ internal class CocoapodsBuildDirs(val project: Project) {
|
||||
val defs: File
|
||||
get() = root.resolve("defs")
|
||||
|
||||
val buildSettings: File
|
||||
get() = root.resolve("buildSettings")
|
||||
|
||||
private val synthetic: File
|
||||
get() = root.resolve("synthetic")
|
||||
|
||||
fun synthetic(kotlinNativeTarget: KotlinNativeTarget) = synthetic.resolve(kotlinNativeTarget.name)
|
||||
|
||||
fun fatFramework(buildType: String) =
|
||||
root.resolve("fat-frameworks/${buildType.toLowerCase()}")
|
||||
}
|
||||
|
||||
internal fun String.asValidFrameworkName() = replace('-', '_')
|
||||
|
||||
internal val KotlinNativeTarget.toBuildSetupTaskName: String
|
||||
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME, disambiguationClassifier)
|
||||
private val KotlinNativeTarget.toPodGenTaskName: String
|
||||
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_GEN_TASK_NAME, disambiguationClassifier)
|
||||
|
||||
internal val KotlinNativeTarget.toBuildDependenciesTaskName: String
|
||||
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_BUILD_DEPENDENCIES_TASK_NAME, disambiguationClassifier)
|
||||
private val KotlinNativeTarget.toSetupBuildTaskName: String
|
||||
get() = lowerCamelCaseName(
|
||||
KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME,
|
||||
disambiguationClassifier
|
||||
)
|
||||
|
||||
|
||||
private val KotlinNativeTarget.toBuildDependenciesTaskName: String
|
||||
get() = lowerCamelCaseName(
|
||||
KotlinCocoapodsPlugin.POD_BUILD_DEPENDENCIES_TASK_NAME,
|
||||
disambiguationClassifier
|
||||
)
|
||||
|
||||
open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
|
||||
@@ -181,7 +199,8 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
moduleNames.add(pod.moduleName)
|
||||
|
||||
val defTask = project.registerTask<DefFileTask>(
|
||||
lowerCamelCaseName("generateDef", pod.moduleName).asValidTaskName()) {
|
||||
lowerCamelCaseName("generateDef", pod.moduleName).asValidTaskName()
|
||||
) {
|
||||
it.pod = pod
|
||||
it.description = "Generates a def file for CocoaPods dependencies with module ${pod.moduleName}"
|
||||
// This task is an implementation detail so we don't add it in any group
|
||||
@@ -199,7 +218,11 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
interop.packageName = "cocoapods.${pod.moduleName}"
|
||||
|
||||
|
||||
if (project.findProperty(TARGET_PROPERTY) == null && project.findProperty(CONFIGURATION_PROPERTY) == null) {
|
||||
if (//TODO ychernyshev improve first check
|
||||
isAvailableToProduceSynthetic()
|
||||
&& project.findProperty(TARGET_PROPERTY) == null
|
||||
&& project.findProperty(CONFIGURATION_PROPERTY) == null
|
||||
) {
|
||||
val podBuildTaskProvider = project.tasks.named(target.toBuildDependenciesTaskName, PodBuildTask::class.java)
|
||||
interopTask.inputs.file(podBuildTaskProvider.get().buildSettingsFileProvider)
|
||||
interopTask.dependsOn(podBuildTaskProvider)
|
||||
@@ -221,24 +244,28 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
// Since we cannot expand the configuration phase of interop tasks
|
||||
// receiving the required environment variables happens on execution phase.
|
||||
// TODO This needs to be fixed to improve UP-TO-DATE checks.
|
||||
if (project.findProperty(TARGET_PROPERTY) == null && project.findProperty(CONFIGURATION_PROPERTY) == null) {
|
||||
if (// TODO ychernyshev improve first check
|
||||
isAvailableToProduceSynthetic()
|
||||
&& project.findProperty(TARGET_PROPERTY) == null
|
||||
&& project.findProperty(CONFIGURATION_PROPERTY) == null
|
||||
) {
|
||||
val podBuildTaskProvider = project.tasks.named(target.toBuildDependenciesTaskName, PodBuildTask::class.java)
|
||||
val buildSettings =
|
||||
podBuildTaskProvider.get().buildSettingsFileProvider.get()
|
||||
?.inputStream()
|
||||
?.use {
|
||||
.inputStream()
|
||||
.use {
|
||||
PodBuildSettingsProperties.readSettingsFromStream(it)
|
||||
}
|
||||
|
||||
buildSettings?.cflags?.let { args ->
|
||||
buildSettings.cflags?.let { args ->
|
||||
// Xcode quotes around paths with spaces.
|
||||
// Here and below we need to split such paths taking this into account.
|
||||
interop.compilerOpts.addAll(args.splitQuotedArgs())
|
||||
}
|
||||
buildSettings?.headerPaths?.let { args ->
|
||||
buildSettings.headerPaths?.let { args ->
|
||||
interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-I$it" })
|
||||
}
|
||||
buildSettings?.frameworkPaths?.let { args ->
|
||||
buildSettings.frameworkPaths?.let { args ->
|
||||
interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-F$it" })
|
||||
}
|
||||
}
|
||||
@@ -253,7 +280,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
project.tasks.register(DUMMY_FRAMEWORK_TASK_NAME, DummyFrameworkTask::class.java) {
|
||||
it.settings = cocoapodsExtension
|
||||
it.cocoapodsExtension = cocoapodsExtension
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,14 +306,34 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
project: Project,
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
|
||||
val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java)
|
||||
|
||||
project.tasks.register(POD_INSTALL_TASK_NAME, PodInstallTask::class.java) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Invokes `pod install` call within Podfile location directory"
|
||||
it.cocoapodsExtension = cocoapodsExtension
|
||||
it.dependsOn(podspecTaskProvider)
|
||||
//TODO avoid subproject task management here
|
||||
project.allprojects.map { it.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java) }
|
||||
.forEach { podspecTaskProvider ->
|
||||
podspecTaskProvider.get().takeIf { task -> task.cocoapodsExtension.needPodspec }
|
||||
?.also { task -> it.inputs.file(task.outputFileProvider) }
|
||||
it.dependsOn(podspecTaskProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerPodGenTask(
|
||||
project: Project, kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
|
||||
val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java)
|
||||
|
||||
kotlinExtension.supportedTargets().all { target ->
|
||||
project.tasks.register(target.toPodGenTaskName, PodGenTask::class.java) {
|
||||
it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
||||
it.podspecProvider = podspecTaskProvider.get().outputFileProvider
|
||||
it.kotlinNativeTarget = target
|
||||
it.cocoapodsExtension = cocoapodsExtension
|
||||
it.dependsOn(podspecTaskProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,16 +343,16 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
|
||||
val podInstallTaskProvider = project.tasks.named(POD_INSTALL_TASK_NAME, PodInstallTask::class.java)
|
||||
|
||||
kotlinExtension.supportedTargets().all { target ->
|
||||
project.tasks.register(target.toBuildSetupTaskName, PodSetupBuildTask::class.java) {
|
||||
|
||||
project.tasks.register(target.toSetupBuildTaskName, PodSetupBuildTask::class.java) {
|
||||
it.group = TASK_GROUP
|
||||
it.kotlinNativeTarget = target
|
||||
it.description = "Collect environment variables from .xcworkspace file"
|
||||
it.cocoapodsExtension = cocoapodsExtension
|
||||
it.podsXcodeProjDirProvider = podInstallTaskProvider.get().podsXcodeProjDirProvider
|
||||
it.dependsOn(podInstallTaskProvider)
|
||||
it.kotlinNativeTarget = target
|
||||
val podGenTaskProvider = project.tasks.named(target.toPodGenTaskName, PodGenTask::class.java)
|
||||
it.podsXcodeProjDirProvider = podGenTaskProvider.get().podsXcodeProjDirProvider
|
||||
it.dependsOn(podGenTaskProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,15 +365,15 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
|
||||
kotlinExtension.supportedTargets().all { target ->
|
||||
|
||||
val podSetupBuildTaskProvider = project.tasks.named(target.toBuildSetupTaskName, PodSetupBuildTask::class.java)
|
||||
val podSetupBuildTaskProvider = project.tasks.named(target.toSetupBuildTaskName, PodSetupBuildTask::class.java)
|
||||
|
||||
project.tasks.register(target.toBuildDependenciesTaskName, PodBuildTask::class.java) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Calls `xcodebuild` on xcworkspace for the pod scheme"
|
||||
it.kotlinNativeTarget = target
|
||||
it.cocoapodsExtension = cocoapodsExtension
|
||||
it.podsXcodeProjDirProvider = (podSetupBuildTaskProvider.get()).podsXcodeProjDirProvider
|
||||
it.buildSettingsFileProvider = (podSetupBuildTaskProvider.get()).buildSettingsFileProvider
|
||||
it.podsXcodeProjDirProvider = podSetupBuildTaskProvider.get().podsXcodeProjDirProvider
|
||||
it.buildSettingsFileProvider = podSetupBuildTaskProvider.get().buildSettingsFileProvider
|
||||
it.dependsOn(podSetupBuildTaskProvider)
|
||||
}
|
||||
}
|
||||
@@ -337,9 +384,11 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
kotlinExtension: KotlinMultiplatformExtension
|
||||
) {
|
||||
|
||||
val podInstallTaskProvider = project.tasks.named(POD_INSTALL_TASK_NAME, PodInstallTask::class.java)
|
||||
project.tasks.register(POD_IMPORT_TASK_NAME) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Called on Gradle sync, depends on Cinterop tasks for every used pod"
|
||||
it.dependsOn(podInstallTaskProvider)
|
||||
|
||||
kotlinExtension.supportedTargets().all { target ->
|
||||
target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).cinterops.all { interop ->
|
||||
@@ -347,7 +396,6 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
it.dependsOn(interopTaskProvider)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,27 +404,40 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
pluginManager.withPlugin("kotlin-multiplatform") {
|
||||
val kotlinExtension = project.multiplatformExtension
|
||||
val cocoapodsExtension = CocoapodsExtension(this)
|
||||
|
||||
kotlinExtension.addExtension(EXTENSION_NAME, cocoapodsExtension)
|
||||
kotlinExtension.addExtension(COCOAPODS_EXTENSION_NAME, cocoapodsExtension)
|
||||
createDefaultFrameworks(kotlinExtension, cocoapodsExtension)
|
||||
registerDummyFrameworkTask(project, cocoapodsExtension)
|
||||
createSyncTask(project, kotlinExtension)
|
||||
registerPodspecTask(project, cocoapodsExtension)
|
||||
registerPodInstallTask(project, cocoapodsExtension)
|
||||
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||
registerPodImportTask(project, kotlinExtension)
|
||||
if (isAvailableToProduceSynthetic()) {
|
||||
registerPodGenTask(project, kotlinExtension, cocoapodsExtension)
|
||||
registerPodInstallTask(project, cocoapodsExtension)
|
||||
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||
registerPodImportTask(project, kotlinExtension)
|
||||
} else {
|
||||
logger.quiet(
|
||||
"""
|
||||
To take advantage of the new functionality for Cocoapods Integration like synchronizing with the Xcode project
|
||||
and supporting dependencies on pods, please install the `cocoapods-generate` plugin for CocoaPods
|
||||
by calling `gem install cocoapods-generate` in terminal.
|
||||
|
||||
More details are available by https://github.com/square/cocoapods-generate
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
createInterops(project, kotlinExtension, cocoapodsExtension)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTENSION_NAME = "cocoapods"
|
||||
const val COCOAPODS_EXTENSION_NAME = "cocoapods"
|
||||
const val TASK_GROUP = "CocoaPods"
|
||||
const val SYNC_TASK_NAME = "syncFramework"
|
||||
const val POD_SPEC_TASK_NAME = "podspec"
|
||||
const val DUMMY_FRAMEWORK_TASK_NAME = "generateDummyFramework"
|
||||
const val POD_INSTALL_TASK_NAME = "podInstall"
|
||||
const val POD_GEN_TASK_NAME = "podGen"
|
||||
const val POD_SETUP_BUILD_TASK_NAME = "podSetupBuild"
|
||||
const val POD_BUILD_DEPENDENCIES_TASK_NAME = "podBuildDependencies"
|
||||
const val POD_IMPORT_TASK_NAME = "podImport"
|
||||
@@ -396,5 +457,14 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
// so we should generate a fat framework with arm32 and arm64 binaries.
|
||||
const val KOTLIN_TARGET_FOR_IOS_DEVICE = "ios_arm"
|
||||
const val KOTLIN_TARGET_FOR_WATCHOS_DEVICE = "watchos_arm"
|
||||
|
||||
fun isAvailableToProduceSynthetic(): Boolean {
|
||||
val gemListProcess = ProcessBuilder("gem", "list").start()
|
||||
val gemListRetCode = gemListProcess.waitFor()
|
||||
val gemListOutput = gemListProcess.inputStream.use {
|
||||
it.reader().readText()
|
||||
}
|
||||
return gemListRetCode == 0 && gemListOutput.contains("cocoapods-generate")
|
||||
}
|
||||
}
|
||||
}
|
||||
+166
-127
@@ -12,150 +12,229 @@ import org.gradle.api.tasks.Optional
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildTask.Companion.toValidSDK
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.InputStream
|
||||
import java.math.BigInteger
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
abstract class AdvancedCocoapodsTask : DefaultTask() {
|
||||
@get:Nested
|
||||
lateinit var cocoapodsExtension: CocoapodsExtension
|
||||
internal val KotlinNativeTarget.toBuildSettingsFileName: String
|
||||
get() = "build-settings-$disambiguationClassifier.properties"
|
||||
|
||||
@TaskAction
|
||||
fun commonInvoke() {
|
||||
podfileCheck(cocoapodsExtension)
|
||||
specificInvoke()
|
||||
internal val KotlinNativeTarget.toValidSDK: String
|
||||
get() = when (konanTarget) {
|
||||
KonanTarget.IOS_X64 -> "iphonesimulator"
|
||||
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iphoneos"
|
||||
KonanTarget.WATCHOS_X86, KonanTarget.WATCHOS_X64 -> "watchsimulator"
|
||||
KonanTarget.WATCHOS_ARM32, KonanTarget.WATCHOS_ARM64 -> "watchos"
|
||||
KonanTarget.TVOS_X64 -> "appletvsimulator"
|
||||
KonanTarget.TVOS_ARM64 -> "appletvos"
|
||||
KonanTarget.MACOS_X64 -> "macosx"
|
||||
else -> throw IllegalArgumentException("Bad target ${konanTarget.name}.")
|
||||
}
|
||||
|
||||
abstract fun specificInvoke()
|
||||
|
||||
private fun podfileCheck(cocoapodsExtension: CocoapodsExtension) {
|
||||
check(cocoapodsExtension.podfile != null) {
|
||||
"Execution of task '$name' requires the path to the Podfile. Specify it in the file ${project.buildFile.absolutePath}."
|
||||
}
|
||||
internal val KotlinNativeTarget.platformLiteral: String
|
||||
get() = when (konanTarget.family) {
|
||||
Family.OSX -> "macos"
|
||||
Family.IOS -> "ios"
|
||||
Family.TVOS -> "tvos"
|
||||
Family.WATCHOS -> "watchos"
|
||||
else -> throw IllegalArgumentException("Unsupported native target '${konanTarget.name}'")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The task takes the path to the Podfile and calls `pod install`
|
||||
* to obtain sources or artifacts for the declared dependencies.
|
||||
* This task is a part of CocoaPods integration infrastructure.
|
||||
*/
|
||||
open class PodInstallTask : AdvancedCocoapodsTask() {
|
||||
|
||||
@get:InputFile
|
||||
@get:Optional
|
||||
internal val podfileProvider: Provider<File?> = project.provider { cocoapodsExtension.podfile }
|
||||
|
||||
@get:OutputDirectory
|
||||
@get:Optional
|
||||
internal val podsXcodeProjDirProvider: Provider<File?> = project.provider {
|
||||
cocoapodsExtension.podfile
|
||||
?.parentFile
|
||||
?.resolve("Pods")
|
||||
?.resolve("Pods.xcodeproj")
|
||||
open class PodInstallTask : DefaultTask() {
|
||||
init {
|
||||
onlyIf { cocoapodsExtension?.podfile != null }
|
||||
}
|
||||
|
||||
override fun specificInvoke() {
|
||||
val podfileDir = podfileProvider.get()!!.parentFile
|
||||
val podInstallProcess = ProcessBuilder("pod", "install").apply {
|
||||
directory(podfileDir)
|
||||
inheritIO()
|
||||
}.start()
|
||||
val podInstallRetCode = podInstallProcess.waitFor()
|
||||
check(podInstallRetCode == 0) { "Unable to run 'pod install', return code $podInstallRetCode" }
|
||||
@get:Optional
|
||||
@get:Nested
|
||||
internal var cocoapodsExtension: CocoapodsExtension? = null
|
||||
|
||||
val podsXcprojFile = podsXcodeProjDirProvider.get()
|
||||
check(podsXcprojFile != null && podsXcprojFile.exists() && podsXcprojFile.isDirectory) {
|
||||
"The directory 'Pods/Pods.xcodeproj' was not created as a result of the `pod install` call."
|
||||
@get:Optional
|
||||
@get:OutputDirectory
|
||||
internal val podsXcodeProjDirProvider: Provider<File>?
|
||||
get() = cocoapodsExtension?.podfile?.let {
|
||||
project.provider { it.parentFile.resolve("Pods").resolve("Pods.xcodeproj") }
|
||||
}
|
||||
|
||||
|
||||
@TaskAction
|
||||
fun doPodInstall() {
|
||||
cocoapodsExtension?.podfile?.parentFile?.also { podfileDir ->
|
||||
val podInstallProcess = ProcessBuilder("pod", "install").apply {
|
||||
directory(podfileDir)
|
||||
}.start()
|
||||
val podInstallRetCode = podInstallProcess.waitFor()
|
||||
val podInstallOutput = podInstallProcess.inputStream.use { it.reader().readText() }
|
||||
|
||||
check(podInstallRetCode == 0) {
|
||||
listOf(
|
||||
"Executing of 'pod install' failed with code $podInstallRetCode.",
|
||||
"Error message:",
|
||||
podInstallOutput
|
||||
).joinToString("\n")
|
||||
}
|
||||
with(podsXcodeProjDirProvider) {
|
||||
check(this != null && get().exists() && get().isDirectory) {
|
||||
"The directory 'Pods/Pods.xcodeproj' was not created as a result of the `pod install` call."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class PodSetupBuildTask : AdvancedCocoapodsTask() {
|
||||
abstract class CocoapodsWithSyntheticTask : DefaultTask() {
|
||||
init {
|
||||
onlyIf {
|
||||
cocoapodsExtension.pods.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var cocoapodsExtension: CocoapodsExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* The task takes the path to the .podspec file and calls `pod gen`
|
||||
* to create synthetic xcode project and workspace.
|
||||
*/
|
||||
open class PodGenTask : CocoapodsWithSyntheticTask() {
|
||||
|
||||
@get:InputFile
|
||||
internal lateinit var podspecProvider: Provider<File>
|
||||
|
||||
@Internal
|
||||
lateinit var kotlinNativeTarget: KotlinNativeTarget
|
||||
|
||||
@get:OutputDirectory
|
||||
internal val podsXcodeProjDirProvider: Provider<File>
|
||||
get() = project.provider {
|
||||
project.cocoapodsBuildDirs.synthetic(kotlinNativeTarget)
|
||||
.resolve(podspecProvider.get().nameWithoutExtension)
|
||||
.resolve("Pods")
|
||||
.resolve("Pods.xcodeproj")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
val podspecDir = podspecProvider.get().parentFile
|
||||
val localPodspecPaths = cocoapodsExtension.pods.mapNotNull { it.podspec?.parentFile?.absolutePath }
|
||||
|
||||
val podGenProcessArgs = listOfNotNull(
|
||||
"pod", "gen",
|
||||
"--platforms=${kotlinNativeTarget.platformLiteral}",
|
||||
"--gen-directory=${project.cocoapodsBuildDirs.synthetic(kotlinNativeTarget).absolutePath}",
|
||||
localPodspecPaths.takeIf { it.isNotEmpty() }?.joinToString(separator = ",")?.let { "--local-sources=$it" },
|
||||
podspecProvider.get().name
|
||||
)
|
||||
|
||||
val podGenProcess = ProcessBuilder(podGenProcessArgs).apply {
|
||||
directory(podspecDir)
|
||||
}.start()
|
||||
val podGenRetCode = podGenProcess.waitFor()
|
||||
val outputText = podGenProcess.inputStream.use { it.reader().readText() }
|
||||
|
||||
check(podGenRetCode == 0) {
|
||||
listOfNotNull(
|
||||
"Executing of '${podGenProcessArgs.joinToString(" ")}' failed with code $podGenRetCode and message:",
|
||||
outputText,
|
||||
outputText.takeIf {
|
||||
it.contains("deployment target")
|
||||
|| it.contains("requested platforms: [\"${kotlinNativeTarget.platformLiteral}\"]")
|
||||
}?.let {
|
||||
"""
|
||||
Tip: try to configure deployment_target for ALL targets as follows:
|
||||
cocoapods {
|
||||
...
|
||||
${kotlinNativeTarget.konanTarget.family.name.toLowerCase()}.deploymentTarget = "..."
|
||||
...
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
).joinToString("\n")
|
||||
}
|
||||
|
||||
val podsXcprojFile = podsXcodeProjDirProvider.get()
|
||||
check(podsXcprojFile.exists() && podsXcprojFile.isDirectory) {
|
||||
"The directory '${podsXcprojFile.path}' was not created as a result of the `pod gen` call."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open class PodSetupBuildTask : CocoapodsWithSyntheticTask() {
|
||||
|
||||
@get:InputDirectory
|
||||
@get:Optional
|
||||
internal lateinit var podsXcodeProjDirProvider: Provider<File?>
|
||||
internal lateinit var podsXcodeProjDirProvider: Provider<File>
|
||||
|
||||
@Internal
|
||||
lateinit var kotlinNativeTarget: KotlinNativeTarget
|
||||
|
||||
@get:OutputFile
|
||||
@get:Optional
|
||||
internal val buildSettingsFileProvider: Provider<File?> =
|
||||
project.provider {
|
||||
project
|
||||
.cocoapodsBuildDirs
|
||||
.root
|
||||
.resolve("buildSettings")
|
||||
.resolve(kotlinNativeTarget.toBuildSettingsFileName)
|
||||
}
|
||||
internal val buildSettingsFileProvider: Provider<File> = project.provider {
|
||||
project.cocoapodsBuildDirs
|
||||
.buildSettings
|
||||
.resolve(kotlinNativeTarget.toBuildSettingsFileName)
|
||||
}
|
||||
|
||||
override fun specificInvoke() {
|
||||
@TaskAction
|
||||
fun setupBuild() {
|
||||
val podsXcodeProjDir = podsXcodeProjDirProvider.get()
|
||||
|
||||
val buildSettingsReceivingCommand = listOf(
|
||||
"xcodebuild", "-showBuildSettings",
|
||||
"-project", podsXcodeProjDir!!.name,
|
||||
"-project", podsXcodeProjDir.name,
|
||||
"-scheme", cocoapodsExtension.frameworkName,
|
||||
"-sdk", kotlinNativeTarget.toValidSDK
|
||||
)
|
||||
|
||||
val buildSettingsProcess = ProcessBuilder(buildSettingsReceivingCommand)
|
||||
.apply {
|
||||
directory(podsXcodeProjDir!!.parentFile)
|
||||
directory(podsXcodeProjDir.parentFile)
|
||||
}.start()
|
||||
|
||||
val buildSettingsRetCode = buildSettingsProcess.waitFor()
|
||||
check(buildSettingsRetCode == 0) {
|
||||
"Unable to run '${buildSettingsReceivingCommand.joinToString(" ")}' return code $buildSettingsRetCode"
|
||||
listOf(
|
||||
"Executing of '${buildSettingsReceivingCommand.joinToString(" ")}' failed with code $buildSettingsRetCode and message:",
|
||||
buildSettingsProcess.errorStream.use { it.reader().readText() }
|
||||
).joinToString("\n")
|
||||
}
|
||||
|
||||
|
||||
val stdOut = buildSettingsProcess.inputStream
|
||||
|
||||
val buildSettingsProperties = PodBuildSettingsProperties.readSettingsFromStream(stdOut)
|
||||
buildSettingsProperties.writeSettings(buildSettingsFileProvider.get()!!)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KotlinNativeTarget.toBuildSettingsFileName: String
|
||||
get() = "build-settings-$disambiguationClassifier.properties"
|
||||
buildSettingsFileProvider.get().let { buildSettingsProperties.writeSettings(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The task compiles external cocoa pods sources.
|
||||
*/
|
||||
open class PodBuildTask : AdvancedCocoapodsTask() {
|
||||
open class PodBuildTask : CocoapodsWithSyntheticTask() {
|
||||
|
||||
@get:InputDirectory
|
||||
@get:Optional
|
||||
internal lateinit var podsXcodeProjDirProvider: Provider<File?>
|
||||
internal lateinit var podsXcodeProjDirProvider: Provider<File>
|
||||
|
||||
@get:InputFile
|
||||
@get:Optional
|
||||
internal lateinit var buildSettingsFileProvider: Provider<File?>
|
||||
internal lateinit var buildSettingsFileProvider: Provider<File>
|
||||
|
||||
@Internal
|
||||
lateinit var kotlinNativeTarget: KotlinNativeTarget
|
||||
|
||||
@get:OutputFile
|
||||
@get:Optional
|
||||
internal val buildDirHashFileProvider: Provider<File?> =
|
||||
project.provider {
|
||||
project
|
||||
.cocoapodsBuildDirs
|
||||
.root
|
||||
.resolve("buildDirHashSums")
|
||||
.resolve(kotlinNativeTarget.toBuildDirHashSumFileName)
|
||||
}
|
||||
@get:OutputDirectory
|
||||
internal var buildDirProvider: Provider<File>? = null
|
||||
|
||||
override fun specificInvoke() {
|
||||
@TaskAction
|
||||
fun buildDependencies() {
|
||||
val podBuildSettings = PodBuildSettingsProperties.readSettingsFromStream(
|
||||
FileInputStream(buildSettingsFileProvider.get())
|
||||
)
|
||||
@@ -166,7 +245,7 @@ open class PodBuildTask : AdvancedCocoapodsTask() {
|
||||
|
||||
val podXcodeBuildCommand = listOf(
|
||||
"xcodebuild",
|
||||
"-project", podsXcodeProjDir!!.name,
|
||||
"-project", podsXcodeProjDir.name,
|
||||
"-scheme", it.moduleName,
|
||||
"-sdk", kotlinNativeTarget.toValidSDK,
|
||||
"-configuration", podBuildSettings.configuration
|
||||
@@ -174,59 +253,19 @@ open class PodBuildTask : AdvancedCocoapodsTask() {
|
||||
|
||||
val podBuildProcess = ProcessBuilder(podXcodeBuildCommand)
|
||||
.apply {
|
||||
directory(podsXcodeProjDir!!.parentFile)
|
||||
directory(podsXcodeProjDir.parentFile)
|
||||
inheritIO()
|
||||
}.start()
|
||||
|
||||
val podBuildRetCode = podBuildProcess.waitFor()
|
||||
check(podBuildRetCode == 0) {
|
||||
"Unable to run '${podXcodeBuildCommand.joinToString(" ")}' return code $podBuildRetCode"
|
||||
listOf(
|
||||
"Executing of '${podXcodeBuildCommand.joinToString(" ")}' failed with code $podBuildRetCode and message:",
|
||||
podBuildProcess.errorStream.use { it.reader().readText() }
|
||||
).joinToString("\n")
|
||||
}
|
||||
}
|
||||
val buildDirHashSumFile = buildDirHashFileProvider.get()!!
|
||||
buildDirHashSumFile!!.parentFile.mkdirs()
|
||||
buildDirHashSumFile!!.createNewFile()
|
||||
check(buildDirHashSumFile!!.exists()) {
|
||||
"Unable to create file ${buildDirHashSumFile.toRelativeString(project.projectDir)}!"
|
||||
}
|
||||
|
||||
buildDirHashSumFile.writeText(getFileChecksumStr(project.file(podBuildSettings.buildDir)))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun getFileChecksumStr(file: File): String {
|
||||
val digest = MessageDigest.getInstance("SHA-1")
|
||||
file.walkTopDown().forEach {
|
||||
val byteArray = ByteArray(1024)
|
||||
var bytesCount = 0
|
||||
if (it.isFile) {
|
||||
val inputStream = it.inputStream()
|
||||
while (inputStream.read(byteArray).also { bt -> bytesCount = bt } != -1) {
|
||||
digest.update(byteArray, 0, bytesCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
val buildDirHashSumStr = BigInteger(1, digest.digest()).toString(16).padStart(32, '0')
|
||||
return buildDirHashSumStr
|
||||
}
|
||||
|
||||
internal val KotlinNativeTarget.toBuildDirHashSumFileName: String
|
||||
get() = "build-dir-hash-$disambiguationClassifier.txt"
|
||||
|
||||
internal val KotlinNativeTarget.toValidSDK: String
|
||||
get() {
|
||||
return when (konanTarget) {
|
||||
KonanTarget.IOS_X64 -> "iphonesimulator"
|
||||
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iphoneos"
|
||||
KonanTarget.WATCHOS_X86, KonanTarget.WATCHOS_X64 -> "watchsimulator"
|
||||
KonanTarget.WATCHOS_ARM32, KonanTarget.WATCHOS_ARM64 -> "watchos"
|
||||
KonanTarget.TVOS_X64 -> "appletvsimulator"
|
||||
KonanTarget.TVOS_ARM64 -> "appletvos"
|
||||
KonanTarget.MACOS_X64 -> "macos"
|
||||
else -> throw Error("Bad target ${konanTarget.name}")
|
||||
}
|
||||
}
|
||||
buildDirProvider = project.provider { project.file(podBuildSettings.buildDir) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+47
-12
@@ -7,11 +7,16 @@
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.wrapper.Wrapper
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension
|
||||
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.GENERATE_WRAPPER_PROPERTY
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.KOTLIN_TARGET_FOR_IOS_DEVICE
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.KOTLIN_TARGET_FOR_WATCHOS_DEVICE
|
||||
@@ -29,13 +34,19 @@ open class PodspecTask : DefaultTask() {
|
||||
private val specName = project.name.asValidFrameworkName()
|
||||
|
||||
@get:OutputFile
|
||||
internal val outputFileProvider: Provider<File> = project.provider { project.file("$specName.podspec") }
|
||||
internal val outputFileProvider: Provider<File>
|
||||
get() = project.provider { project.file("$specName.podspec") }
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var cocoapodsExtension: CocoapodsExtension
|
||||
|
||||
init {
|
||||
onlyIf { cocoapodsExtension.needPodspec }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
|
||||
val frameworkDir = project.cocoapodsBuildDirs.framework.relativeTo(outputFileProvider.get().parentFile).path
|
||||
val dependencies = cocoapodsExtension.pods.map { pod ->
|
||||
val versionSuffix = if (pod.version != null) ", '${pod.version}'" else ""
|
||||
@@ -56,6 +67,13 @@ open class PodspecTask : DefaultTask() {
|
||||
val gradleCommand = "\$REPO_ROOT/${gradleWrapper!!.toRelativeString(project.projectDir)}"
|
||||
val syncTask = "${project.path}:$SYNC_TASK_NAME"
|
||||
|
||||
val deploymentTargets = run {
|
||||
with(cocoapodsExtension) {
|
||||
listOf(ios, osx, tvos, watchos).filter { it.deploymentTarget != null }.joinToString("\n") {
|
||||
"| spec.${it.name}.deployment_target = '${it.deploymentTarget}'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with(outputFileProvider.get()) {
|
||||
writeText(
|
||||
@@ -74,6 +92,8 @@ open class PodspecTask : DefaultTask() {
|
||||
| spec.libraries = "c++"
|
||||
| spec.module_name = "#{spec.name}_umbrella"
|
||||
|
|
||||
$deploymentTargets
|
||||
|
|
||||
$dependencies
|
||||
|
|
||||
| spec.pod_target_xcconfig = {
|
||||
@@ -93,7 +113,7 @@ open class PodspecTask : DefaultTask() {
|
||||
| :shell_path => '/bin/sh',
|
||||
| :script => <<-SCRIPT
|
||||
| set -ev
|
||||
| REPO_ROOT="${'$'}PODS_TARGET_SRCROOT/"
|
||||
| REPO_ROOT="${'$'}PODS_TARGET_SRCROOT"
|
||||
| "$gradleCommand" -p "${'$'}REPO_ROOT" $syncTask \
|
||||
| -P${KotlinCocoapodsPlugin.TARGET_PROPERTY}=${'$'}KOTLIN_TARGET \
|
||||
| -P${KotlinCocoapodsPlugin.CONFIGURATION_PROPERTY}=${'$'}CONFIGURATION \
|
||||
@@ -107,17 +127,30 @@ open class PodspecTask : DefaultTask() {
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
logger.quiet(
|
||||
"""
|
||||
Generated a podspec file at: ${absolutePath}.
|
||||
To include it in your Xcode project, add the following dependency snippet in your Podfile:
|
||||
if (hasPodfileOwnOrParent(project)) {
|
||||
logger.quiet(
|
||||
"""
|
||||
Generated a podspec file at: ${absolutePath}.
|
||||
To include it in your Xcode project, check that the following dependency snippet exists in your Podfile:
|
||||
|
||||
pod '$specName', :path => '${parentFile.absolutePath}'
|
||||
pod '$specName', :path => '${parentFile.absolutePath}'
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KotlinMultiplatformExtension?.cocoapodsExtensionOrNull: CocoapodsExtension?
|
||||
get() = (this as? ExtensionAware)?.extensions?.findByName(COCOAPODS_EXTENSION_NAME) as? CocoapodsExtension
|
||||
|
||||
private fun hasPodfileOwnOrParent(project: Project): Boolean =
|
||||
if (project.rootProject == project) project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null
|
||||
else project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null
|
||||
|| (project.parent?.let { hasPodfileOwnOrParent(it) } ?: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,10 +170,10 @@ open class DummyFrameworkTask : DefaultTask() {
|
||||
val destinationDir = project.cocoapodsBuildDirs.framework
|
||||
|
||||
@Input
|
||||
val frameworkNameProvider: Provider<String> = project.provider { settings.frameworkName }
|
||||
val frameworkNameProvider: Provider<String> = project.provider { cocoapodsExtension.frameworkName }
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var settings: CocoapodsExtension
|
||||
internal lateinit var cocoapodsExtension: CocoapodsExtension
|
||||
|
||||
private val frameworkDir: File
|
||||
get() = destinationDir.resolve("${frameworkNameProvider.get()}.framework")
|
||||
@@ -157,8 +190,10 @@ open class DummyFrameworkTask : DefaultTask() {
|
||||
private fun copyTextResource(from: String, to: File, transform: (String) -> String = { it }) {
|
||||
to.parentFile.mkdirs()
|
||||
to.printWriter().use { file ->
|
||||
javaClass.getResourceAsStream(from).reader().forEachLine {
|
||||
file.println(transform(it))
|
||||
javaClass.getResourceAsStream(from).use {
|
||||
it.reader().forEachLine { str ->
|
||||
file.println(transform(str))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user