Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor KMP iOS build #796

Merged
merged 10 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/ios-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-java
- name: Set up XCFramework arch filter
run: echo "arch=arm64" >> local.properties
- run: make build-app-debug
working-directory: app-ios
- run: make test-app-debug
Expand Down
21 changes: 17 additions & 4 deletions app-ios-shared/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import io.github.droidkaigi.confsched.primitive.Arch
import io.github.droidkaigi.confsched.primitive.activeArch
import org.jetbrains.compose.ComposePlugin.CommonComponentsDependencies
import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
Expand All @@ -15,6 +17,8 @@ kotlin {
val frameworkName = "shared"
val xcf = XCFramework(frameworkName)

val activeArch = project.activeArch
logger.lifecycle("activeArch: $activeArch")
targets.filterIsInstance<KotlinNativeTarget>()
.forEach {
it.binaries {
Expand All @@ -27,10 +31,19 @@ kotlin {
binaryOption("bundleVersion", version.toString())
binaryOption("bundleShortVersionString", version.toString())

val includeToXCF = if (project.properties["app.ios.shared.debug"] == "true") {
(this.target.name == "iosSimulatorArm64" && this.debuggable) || (this.target.name == "iosArm64" && this.debuggable)
} else {
true
val includeToXCF = when (activeArch) {
Arch.ARM -> {
this.target.name.contains("iosArm64") || this.target.name.contains("iosSimulatorArm64")
}
Arch.ARM_SIMULATOR_DEBUG -> {
this.target.name.contains("iosSimulatorArm64") && this.debuggable && !this.optimized
}
Arch.X86 -> {
this.target.name.contains("iosX64")
}
Arch.ALL -> {
true
}
}
if (includeToXCF) {
xcf.add(this)
Expand Down
10 changes: 5 additions & 5 deletions app-ios/App/App.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
830BFA7C2C74EBF40017A600 /* compose-resources in Resources */ = {isa = PBXBuildFile; fileRef = 830BFA7B2C74EBF40017A600 /* compose-resources */; };
83CD07FE2C7B1F5400CDEFDB /* compose-resources in Resources */ = {isa = PBXBuildFile; fileRef = 83CD07FD2C7B1F5400CDEFDB /* compose-resources */; };
8C31F46B2BF6909A003F1BBA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8C31F46A2BF6909A003F1BBA /* GoogleService-Info.plist */; };
8C7074772C7791BD00FD4F39 /* ci_post_clone.sh in Resources */ = {isa = PBXBuildFile; fileRef = 8C7074762C7791BD00FD4F39 /* ci_post_clone.sh */; };
8C7074792C7791DF00FD4F39 /* ci_pre_xcodebuild.sh in Resources */ = {isa = PBXBuildFile; fileRef = 8C7074782C7791DF00FD4F39 /* ci_pre_xcodebuild.sh */; };
Expand All @@ -18,7 +18,7 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
830BFA7B2C74EBF40017A600 /* compose-resources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "compose-resources"; path = "../../app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosSimulatorArm64/compose-resources"; sourceTree = "<group>"; };
83CD07FD2C7B1F5400CDEFDB /* compose-resources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "compose-resources"; path = "../../app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/compose-resources"; sourceTree = "<group>"; };
8C31F46A2BF6909A003F1BBA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
8C7074762C7791BD00FD4F39 /* ci_post_clone.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_post_clone.sh; sourceTree = "<group>"; };
8C7074782C7791DF00FD4F39 /* ci_pre_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_pre_xcodebuild.sh; sourceTree = "<group>"; };
Expand Down Expand Up @@ -57,8 +57,8 @@
8C772B0C2BCBCBCA00F2BADC = {
isa = PBXGroup;
children = (
83CD07FD2C7B1F5400CDEFDB /* compose-resources */,
8C7074752C77919300FD4F39 /* ci_scripts */,
830BFA7B2C74EBF40017A600 /* compose-resources */,
C412816C2C149FB500B458D1 /* DroidKaigi2024App-Info.plist */,
8C7DACC22BCBD111002C298A /* App */,
8C7DACC12BCBD0F1002C298A /* app-ios */,
Expand Down Expand Up @@ -171,7 +171,7 @@
8C7DACB72BCBCCB0002C298A /* Preview Assets.xcassets in Resources */,
8C31F46B2BF6909A003F1BBA /* GoogleService-Info.plist in Resources */,
8C7074772C7791BD00FD4F39 /* ci_post_clone.sh in Resources */,
830BFA7C2C74EBF40017A600 /* compose-resources in Resources */,
83CD07FE2C7B1F5400CDEFDB /* compose-resources in Resources */,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current resource is like this
image

);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -194,7 +194,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/zsh;
shellScript = "cd ${SRCROOT}/../..\n\n./gradlew assembleSharedXCFramework --no-configuration-cache\n./gradlew iosSimulatorArm64AggregateResources --no-configuration-cache\n./gradlew iosArm64AggregateResources --no-configuration-cache\n\nSIMULATOR_RESOURCE_DIR=\"./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosSimulatorArm64\"\nDEVICE_RESOURCE_DIR=\"./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosArm64\"\n\nmkdir -p ${SIMULATOR_RESOURCE_DIR}/composeResources\nmkdir -p ${DEVICE_RESOURCE_DIR}/composeResources\n\nmkdir -p ${SIMULATOR_RESOURCE_DIR}/compose-resources\nmkdir -p ${DEVICE_RESOURCE_DIR}/compose-resources\n\ncp -R ${SIMULATOR_RESOURCE_DIR}/composeResources ${SIMULATOR_RESOURCE_DIR}/compose-resources\ncp -R ${DEVICE_RESOURCE_DIR}/composeResources ${DEVICE_RESOURCE_DIR}/compose-resources\n";
shellScript = "cd ${SRCROOT}/../..\n\n./build_xcframework_with_xcode_environment_variable.sh\n./gradlew iosSimulatorArm64AggregateResources --no-configuration-cache\n./gradlew iosX64AggregateResources --no-configuration-cache\n\nARM_RESOURCE_DIR=\"./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosSimulatorArm64\"\nX64_RESOURCE_DIR=\"./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosX64\"\nRESOURCE_DIR=\"./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/compose-resources\"\n\nmkdir -p ${ARM_RESOURCE_DIR}/composeResources\nmkdir -p ${X64_RESOURCE_DIR}/composeResources\n\nmkdir -p ${RESOURCE_DIR}\n\ncp -R ${ARM_RESOURCE_DIR}/composeResources ${RESOURCE_DIR}\n\n# Check if X64 resources exist and are not empty\nif [ -d \"${X64_RESOURCE_DIR}/composeResources\" ] && [ \"$(ls -A \"${X64_RESOURCE_DIR}/composeResources\")\" ]; then\n # Copy X64 resources\n cp -R \"${X64_RESOURCE_DIR}/composeResources\" \"${RESOURCE_DIR}\"\nelse\n echo \"Warning: X64_RESOURCE_DIR is empty or does not exist. Skipping X64 resource copy.\"\nfi\n";
Copy link
Member Author

@takahirom takahirom Aug 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current script is like this

cd ${SRCROOT}/../..

./build_xcframework_with_xcode_environment_variable.sh
./gradlew iosSimulatorArm64AggregateResources --no-configuration-cache
./gradlew iosX64AggregateResources --no-configuration-cache

ARM_RESOURCE_DIR="./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosSimulatorArm64"
X64_RESOURCE_DIR="./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/iosX64"
RESOURCE_DIR="./app-ios-shared/build/kotlin-multiplatform-resources/aggregated-resources/compose-resources"

mkdir -p ${ARM_RESOURCE_DIR}/composeResources
mkdir -p ${X64_RESOURCE_DIR}/composeResources

mkdir -p ${RESOURCE_DIR}

cp -R ${ARM_RESOURCE_DIR}/composeResources ${RESOURCE_DIR}

# Check if X64 resources exist and are not empty
if [ -d "${X64_RESOURCE_DIR}/composeResources" ] && [ "$(ls -A "${X64_RESOURCE_DIR}/composeResources")" ]; then
    # Copy X64 resources
    cp -R "${X64_RESOURCE_DIR}/composeResources" "${RESOURCE_DIR}"
else
    echo "Warning: X64_RESOURCE_DIR is empty or does not exist. Skipping X64 resource copy."
fi

};
/* End PBXShellScriptBuildPhase section */

Expand Down
9 changes: 7 additions & 2 deletions app-ios/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ build-kmp-module:
cd .. && \
./gradlew app-ios-shared:assembleSharedXCFramework --no-configuration-cache
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now build-kmp-module build all architectures.


.PHONY: build-kmp-module-debug
build-kmp-module-debug:
cd .. && \
./gradlew app-ios-shared:assembleSharedXCFramework -Papp.ios.shared.arch=arm64SimulatorDebug --no-configuration-cache

.PHONY: build-app-debug
build-app-debug: build-kmp-module
build-app-debug: build-kmp-module-debug
set -o pipefail && \
xcodebuild -project $(PROJECT_FILE) \
-scheme $(SCHEME_NAME_APP) \
Expand All @@ -39,7 +44,7 @@ test-app-debug:
.PHONY: bootstrap
bootstrap:
make setup && \
make build-kmp-module && \
make build-kmp-module-debug && \
make open

# Gradle Utility
Expand Down
20 changes: 20 additions & 0 deletions app-ios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,23 @@ Sometimes an error will occur if the JDK versions do not match. In the case of a
You select Xcode > Settings > Locations and set your $JAVA_HOME path manually.

JFYI: https://qiita.com/nacho4d/items/6d04c9287c55c26fca95

### Case3: You are using x86_64 Mac and want to build the project

If you are using x86_64 Mac and want to build the project, you need to specify the architecture when building XCFramework.

```shell
./gradlew app-ios-shared:assembleSharedXCFramework -Papp.ios.shared.arch=x86_64 --no-configuration-cache
```

Then, you can build the project with Xcode.

### Case4: Want to build the project for the device

If you want to build the project for the device, you need to specify the architecture when building XCFramework.

```shell
./gradlew app-ios-shared:assembleSharedXCFramework -Papp.ios.shared.arch=arm64 --no-configuration-cache
```

Then, you can build the project with Xcode.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.droidkaigi.confsched.primitive

import io.github.droidkaigi.confsched.primitive.Arch.ALL
import io.github.droidkaigi.confsched.primitive.Arch.ARM
import io.github.droidkaigi.confsched.primitive.Arch.ARM_SIMULATOR_DEBUG
import io.github.droidkaigi.confsched.primitive.Arch.X86
import org.gradle.api.Plugin
import org.gradle.api.Project
Expand All @@ -26,11 +27,21 @@ class KmpIosPlugin : Plugin<Project> {
"-linker-option", "-framework", "-linker-option", "CoreGraphics",
)
when (activeArch) {
ARM -> iosSimulatorArm64 {
ARM -> {
iosSimulatorArm64 {
binaries.forEach {
it.freeCompilerArgs += simulatorLinkerOptions
}
}
iosArm64()
}

ARM_SIMULATOR_DEBUG -> iosSimulatorArm64 {
binaries.forEach {
it.freeCompilerArgs += simulatorLinkerOptions
}
}

X86 -> iosX64()
ALL -> {
iosArm64()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.github.droidkaigi.confsched.primitive
import com.google.devtools.ksp.gradle.KspTaskNative
import io.github.droidkaigi.confsched.primitive.Arch.ALL
import io.github.droidkaigi.confsched.primitive.Arch.ARM
import io.github.droidkaigi.confsched.primitive.Arch.ARM_SIMULATOR_DEBUG
import io.github.droidkaigi.confsched.primitive.Arch.X86
import org.gradle.api.Plugin
import org.gradle.api.Project
Expand Down Expand Up @@ -35,7 +36,12 @@ class KmpKtorfitPlugin : Plugin<Project> {

dependencies {
val iosConfigs = when (activeArch) {
ARM -> listOf("IosSimulatorArm64")
ARM -> listOf(
"IosArm64",
"IosSimulatorArm64"
)

ARM_SIMULATOR_DEBUG -> listOf("IosSimulatorArm64")
X86 -> listOf("IosX64")
ALL -> listOf(
"IosArm64",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import java.util.Properties

enum class Arch(val arch: String?) {
ARM("arm64"),
ARM_SIMULATOR_DEBUG("arm64SimulatorDebug"),
X86("x86_64"),
ALL(null),
;

companion object {
fun findByArch(arch: String?): Arch {
println("input arch: $arch")
return values().firstOrNull { it.arch == arch } ?: ALL
}
}
Expand All @@ -23,5 +25,5 @@ val Project.activeArch
Properties().apply {
load(it.reader(Charsets.UTF_8))
}.getProperty("arch")
} ?: System.getenv("arch")
} ?: properties["app.ios.shared.arch"] as? String ?: System.getenv("arch")
)
33 changes: 33 additions & 0 deletions build_xcframework_with_xcode_environment_variable.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

# Check if SDK_NAME and ARCHS environment variables are set
if [ -z "$SDK_NAME" ] || [ -z "$ARCHS" ]; then
echo "Error: SDK_NAME or ARCHS environment variable is not set"
exit 1
fi

# Initialize the target architecture
target_arch=""

# Determine the target architecture based on SDK_NAME and ARCHS
if [[ "$SDK_NAME" == *"simulator"* ]]; then
if [[ "$ARCHS" == *"arm64"* ]]; then
target_arch="arm64SimulatorDebug"
elif [[ "$ARCHS" == *"x86_64"* ]]; then
target_arch="x86_64"
fi
elif [[ "$SDK_NAME" == *"iphoneos"* ]] && [[ "$ARCHS" == *"arm64"* ]]; then
target_arch="arm64"
fi

# Check if a valid target architecture was determined
if [ -z "$target_arch" ]; then
echo "Error: Unable to determine target architecture from SDK_NAME=$SDK_NAME and ARCHS=$ARCHS"
exit 1
fi

# Execute Gradle command with the determined architecture
echo "Building for architecture: $target_arch"
./gradlew assembleSharedXCFramework --no-configuration-cache -Papp.ios.shared.arch=$target_arch

echo "Build completed for $target_arch"
3 changes: 0 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# operation
app.ios.shared.debug=true

# gradle
org.gradle.jvmargs=-Xmx6048m -Dfile.encoding=UTF-8
org.gradle.configureondemand=true
Expand Down
Loading