Friday, May 20, 2022
HomeiOS Developmentios - Utilizing KMM shared library to be used in XCode offers...

ios – Utilizing KMM shared library to be used in XCode offers a number of warnings when constructing in XCode


Using KMM shared library for use in XCode gives several warnings when building in XCode

First let me explain what I did in order provide a better understanding of what I did and where I run into some problems building my shared KMM library with XCode.

I've created an Android project using Android Studio on my Windows PC for Phone, TV and Wear devices all three utilizing a shared module. I also wanted to build an iOS App, so I used Android Studio on a Mac to create a new KMM Application. I've added my shared module to this KMM application and started to build the iOS App. When that was successful I added an App to run on the Apple Watch, so I used XCode to manually add a (File -> New -> Target…) Watch App for iOS App. I configured it, did some basic coding/plumbing, build it and all was working fine.

The shared module was slighly changed to make it work with Android in combination with XCode and I have added it to the Podfile (I also use Firebase in my project):

target 'XYZ' do
  use_frameworks!
  platform :ios, '15.0'
  pod 'shared', :path => '../shared'
  
  # add pods for desired Firebase products
  # https://firebase.google.com/docs/ios/setup#available-pods
  pod 'Firebase/Messaging'
  pod 'Firebase/Analytics'
  pod 'Firebase/InAppMessaging'
end

target 'WatchXYZ' do
  use_frameworks!
  platform :watchos, '8.0'
  pod 'shared', :path => '../shared'
  
  # add pods for desired Firebase products
  # https://firebase.google.com/docs/ios/setup#available-pods
  pod 'Firebase/Messaging'
  #pod 'Firebase/Analytics'
  #pod 'Firebase/InAppMessaging'
end

target 'WatchXYZ WatchKit Extension' do
  use_frameworks!
  platform :watchos, '8.0'
  pod 'shared', :path => '../shared'

  # add pods for desired Firebase products
  # https://firebase.google.com/docs/ios/setup#available-pods
  pod 'Firebase/Messaging'
  #pod 'Firebase/Analytics'
  #pod 'Firebase/InAppMessaging'
end

In the shared src directory there are four sub-directories: androidMain, commonMain, iosMain and watchosMain. The build.gradle.kts in this directory looks like this:

import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget

plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
    id("kotlin-parcelize")
    kotlin("plugin.serialization") version "1.4.10"
}

version = "1.0"

kotlin {
    android()

    val iosTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = when {
        System.getenv("SDK_NAME")?.startsWith("iphoneos") == true -> ::iosArm64
        System.getenv("NATIVE_ARCH")?.startsWith("arm") == true -> ::iosSimulatorArm64
        else -> ::iosX64
    }

    iosTarget("ios") {}

    watchos()

    cocoapods {
        summary = "Some description for the Shared Module"
        homepage = "Link to the Shared Module homepage"
        ios.deploymentTarget = "15.0"
        watchos.deploymentTarget = "8.0"
        framework {
            baseName = "shared"
        }
        podfile = project.file("../iosApp/Podfile")
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
                implementation("io.ktor:ktor-client-core:1.6.7")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("com.google.android.material:material:1.4.0")
                implementation("io.ktor:ktor-client-android:1.6.7")
            }
        }
        // Workaround for:
        //
        // The Kotlin source set androidAndroidTestRelease was configured but not added to any
        // Kotlin compilation. You can add a source set to a target's compilation by connecting it
        // with the compilation's default source set using 'dependsOn'.
        // See https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#connecting-source-sets
        //
        // This workaround includes `dependsOn(androidAndroidTestRelease)` in the `androidTest` sourceSet.
        val androidAndroidTestRelease by getting
        val androidTest by getting {
            dependsOn(androidAndroidTestRelease)
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.2")
            }
        }
        val iosMain by getting {
            dependencies {
                //implementation("io.ktor:ktor-client-ios:1.6.7")
            }
        }
        val iosTest by getting
        val watchosMain by getting {
            dependencies {
                //implementation("io.ktor:ktor-client-ios:1.6.7")
            }
        }
        val watchosTest by getting
    }
}

android {
    compileSdk = 30
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 28
        targetSdk = 30
    }
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
    kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}

Although I've created the KMM Application with an older version of Android Studio, the current version is Arctic Fox 2020.3.1 patch 4. With XCode 13.2.1 I can build this project for running on my iPhone 7 device with iOS 15.2 and running it in the Simulator. The Mac is an iMac (Retina 5K, 27-inch, Late 2015) with macOS Monterey 12.1. I don't have an Apple Watch (yet).

Executing commands like pod install and/or pod update help me with getting the shared library to work in XCode. All is building and working beautifully, no issues so far.

When building for device or phone or watch Simulators I get some warnings. I was wondering if these are bad and if these can be fixed.

When building for iPhone device I get 5100+ warnings that are something like:
warning: (arm64) could not find object file symbol for symbol _kfun:io.ktor.utils.io.<get-EXPECTED_CAPACITY>#internal
and
warning: (arm64) could not find object file symbol for symbol _kfun:io.ktor.utils.io.ByteChannelSequentialBase#<get-writable>(){}io.ktor.utils.io.core.BytePacketBuilder

Only remark here is that when building for iOS or watchOS Simulators I get the 2 warnings:
From ‘XYZ' App:
warning: (x86_64) could not find object file symbol for symbol __Konan_init_io.ktor:ktor-io-cinterop-sockets
From ‘WatchXYZ WatchKit Extension':
ld: warning: ignoring file /Users/bash/AndroidStudioProjects/XYZ/shared/build/cocoapods/framework/shared.framework/shared, building for watchOS Simulator-arm64 but attempting to link with file built for watchOS Simulator-x86_64

I tried the following:
Build Active Architecture Only is put to Yes for Release in the Build Settings on ‘XYZ' Project (Debug was already set on Yes). After this the behaviour of XCode becomes unpredictable. After a restart and executing a build command for the iPhone I get 4 simlar errors.

Errors (listed just one, others are similar):

Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_SharedClass1", referenced from:
      objc-class-ref in MyView.o

Changing the setting back and forth and performing another build resolves this error. But after a restart its back again. To have this resolved I have to delete the setting alltogether. Only then I'm back to square one.

Does anyone have a clue on how bad my warnings are and if these can be resolved somehow?

Thank you in advance.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments