5

as Apple announced that Xcode Cloud is now available for all developers, I tried to set it up for a Kotlin Multiplatform project. The start was a little bit hard tbh. Currently I am facing following problem during a simple test action:

The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.
Command PhaseScriptExecution failed with a nonzero exit code

So I tried to install a jdk during the ci_post_clone.sh phase. The output of java -version after the installation on the Xcode Cloud is the following:

openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
Installed java

also ./gradlew -v output:


Showing All Messages
------------------------------------------------------------

Gradle 7.4.2

------------------------------------------------------------
Kotlin:       1.5.31
Groovy:       3.0.9
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          17.0.2 (Oracle Corporation 17.0.2+8-86)
OS:           Mac OS X 12.4 x86_64

Nevertheless, I still get the same error. Is this maybe a restriction by Apple?

Any ideas?

HangarRash
  • 7,314
  • 5
  • 5
  • 32
kaulex
  • 2,921
  • 3
  • 11
  • 38

3 Answers3

3

Basically we install a JDK through a tar ball into the project folder using ci_post_clone.sh. We choose the project folder because we have control over this directory, contrary to for example installing java through brew (where you would have to symlink the java install into a system directory, which isn't allowed (https://developer.apple.com/documentation/xcode/making-dependencies-available-to-xcode-cloud)

Note You can use custom build scripts to perform a variety of tasks, but you can’t obtain administrator privileges by using sudo.

This is the script we use:

#!/bin/sh

root_dir=$CI_WORKSPACE_PATH
repo_dir=$CI_PRIMARY_REPOSITORY_PATH
jdk_dir="${CI_DERIVED_DATA_PATH}/JDK"

gradle_dir="${repo_dir}/Common"
cache_dir="${CI_DERIVED_DATA_PATH}/.gradle"

jdk_version="20.0.1"

# Check if we stored gradle caches in DerivedData.
recover_cache_files() {
    
    echo "\nRecover cache files"

    if [ ! -d $cache_dir ]; then
        echo " - No valid caches found, skipping"
        return 0
    fi

    echo " - Copying gradle cache to ${gradle_dir}"
    rm -rf "${gradle_dir}/.gradle"
    cp -r $cache_dir $gradle_dir

    return 0
}

# Install the JDK
install_jdk_if_needed() {

    echo "\nInstall JDK if needed"

    if [[ $(uname -m) == "arm64" ]]; then
        echo " - Detected M1"
        arch_type="macos-aarch64"
    else
        echo " - Detected Intel"
        arch_type="macos-x64"
    fi

    # Location of version / arch detection file.
    detect_loc="${jdk_dir}/.${jdk_version}.${arch_type}"

    if [ -f $detect_loc ]; then
        echo " - Found a valid JDK installation, skipping install"
        return 0
    fi

    echo " - No valid JDK installation found, installing..."

    tar_name="jdk-${jdk_version}_${arch_type}_bin.tar.gz"

    # Download and un-tar JDK to our defined location.
    curl -OL "https://download.oracle.com/java/20/archive/${tar_name}"
    tar xzf $tar_name -C $root_dir

    # Move the JDK to our desired location.
    rm -rf $jdk_dir
    mkdir -p $jdk_dir
    mv "${root_dir}/jdk-${jdk_version}.jdk/Contents/Home" $jdk_dir

    # Some cleanup.
    rm -r "${root_dir}/jdk-${jdk_version}.jdk"
    rm $tar_name

    # Add the detection file for subsequent builds.
    touch $detect_loc

    echo " - Set JAVA_HOME in Xcode Cloud to ${jdk_dir}/Home"

    return 0
}

recover_cache_files
install_jdk_if_needed
MrJre
  • 7,082
  • 7
  • 53
  • 66
2

I use a very simple script relying on SDK!Man for this

#!/usr/bin/env bash
brew install cocoapods
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 19.0.1-tem

# cd into actual project root
cd ../../../
./gradlew app:ios:podinstall

Note that if you want to use java in an XCode build, which you probabbly do you need to set the following environment variable

JAVA_HOME=/Users/local/.sdkman/candidates/java/current
0

I was able to get this working using an env variable within the Xcode Cloud Workflow, installing a java runtime using brew, and modifying a gradle property.

Within the ci_post_clone.sh, I ran:

#!/bin/sh

brew install openjdk@11

Within the environment variable section in the Xcode Cloud workflow I added:

JAVA_HOME=/usr/local/opt/openjdk@11

Within my gradle.properties file I added:

org.gradle.java.home=/usr/local/opt/openjdk@11

This allowed the application to build successfully within Xcode Cloud.