https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
d

Dana Haukoos

10/19/2020, 5:17 PM
I've created the example KMM Hello World app described at Create your first multiplatform application. Next I created a new KMM Module via AndroidStudio's File->New->New Module...->KMM Shared Module, and named it kmmsharedmodule. I edited that to return the date using system libraries for each platform (referencing code snippets from Getting started with Kotlin Multiplatform.) Exactly how do I edit my build.gradle files to make the overall app dependent on kmmsharedmodule? I'm hoping it can be configured to automatically generate both Android and iOS libraries for this module, but I haven't found an example describing this specifically.
k

kpgalligan

10/20/2020, 2:39 PM
It'll be easier to describe if I can see your actual code. In summary, if the shared module is in the same project as the android, us a project dependency for android (https://github.com/touchlab/KaMPKit/blob/master/app/build.gradle.kts#L42), and create an Xcode framework for iOS. There are multiple ways to configure that, so it'll depend on how that's configured.
d

Dana Haukoos

10/23/2020, 8:05 PM
With Russell's assistance, got that simple shared module added as a dependency to the MP app; this now builds and runs as intended. Next I added another KMM module and began adding some code for an http web service call. When I attempt to build with this module added, I'm getting this error:
Task androidAppvalidateSigningDebug UP-TO-DATE
Task androidAppmergeDebugJavaResource FAILED
FAILURE: Build failed with an exception. * What went wrong: Execution failed for task 'androidAppmergeDebugJavaResource'.
A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> More than one file was found with OS independent path 'META-INF/DEPENDENCIES'. I found and tried this https://www.programmersought.com/article/17391741333/, but that doesn't even pass the syntax checker. Did some regression checking: If I comment everything with this newer module out, it builds again. If I comment out the original shared module and just build with this new one, the error returns.
r

russhwolf

10/26/2020, 5:32 PM
That snippet is using Gradle's Groovy syntax and I think your build scripts are in Kotlin. Try something like this
Copy code
android {
    // ...
    packagingOptions {
        exclude("META_INF/*")
    }
}
d

Dana Haukoos

10/26/2020, 5:36 PM
Thanks for the response Russell. I've gotten past this problem, and I've made some progress on a test for doing an example web service call with KMM. I'm taking the path of trying it with expect/actual, and I have a nominally working example on the Android side of things. I'm now wanting to do the actual part on the iOS side of things. ..
To get started, I'm thinking I need some dependency for the iOS core libraries on networking, e.g. to give me things like URLSessionConfiguration and URLSession. Am I imagining this correctly?
r

russhwolf

10/26/2020, 5:43 PM
You should have access to those in your iOS source. It uses the objective-C naming style rather than Swift, so you'll see (for example)
NSURLSession
in the
platform.Foundation
package
d

Dana Haukoos

10/26/2020, 5:52 PM
Right, I see from https://kotlinlang.org/docs/mobile/connect-to-platform-specific-apis.html that I need //iOS import platform.Foundation.* import platform.darwin.NSObject What I'm not yet grasping in the equivalent setup to adding the gradle dependency in Android to make those import statements "functional". Haven't really digested the info at https://kotlinlang.org/docs/mobile/add-dependencies.html#without-cocoapods (in case that's part of the answer).
r

russhwolf

10/26/2020, 5:52 PM
They should work out-of-the-box
Those aren't third-party dependencies. They're part of the iOS platform
d

Dana Haukoos

10/26/2020, 5:56 PM
What do I need to do to resolve this?
r

russhwolf

10/26/2020, 5:57 PM
do
NSURLSession
instead of
URLSession
d

Dana Haukoos

10/26/2020, 5:59 PM
Ah, now I'm tracking, thanks!
👍 1
So here's where I'm stuck on my iOS actual implementation:
Copy code
actual fun getUser(email: String, hostToUse: String): String {

    //<https://stackoverflow.com/questions/3566516/simple-http-post-example-in-objective-c/3566539>
    // <https://blog.jetbrains.com/kotlin/2018/04/kotlinnative-v0-7-released-smoother-interop-frozen-objects-optimisations-and-more/>

    val url = "https://$hostToUse/user/get"
    println("The url is " + url.toString())
    val postString = "data={\"email\":\"$email\"}" as NSString
    println("The postString is " + postString)

    val nsUrl = NSURL.URLWithString(url) as NSURL
    val postData = (postString).dataUsingEncoding(NSUTF8StringEncoding)!!
    val request = NSMutableURLRequest.requestWithURL(nsUrl)
    request.setTimeoutInterval(120.0)
    request.HTTPMethod = "POST"
    request.HTTPBody = postData

    // <https://github.com/ktorio/ktor/blob/master/ktor-client/ktor-client-ios/darwin/src/io/ktor/client/engine/ios/IosClientEngine.kt>
    // <http://hayageek.com/ios-nsurlsession-example/#get-post> //#3.2

    var result : String = "None"
    //val task = session.dataTaskWithRequest(request)
    val task = NSURLSession.sharedSession.dataTaskWithRequest(request) {
            nsData: NSData?, nsURLResponse: NSURLResponse?, nsError: NSError? ->

        if (nsError != null) {
            val message = "The response is: " + nsURLResponse?.description()  + ", error is: " + nsError.description()
            println(message)
        }
        result = nsData.toString()
        println("The data is: " + result)

    }
    task.resume()
    return "The result is: " + result
This compiles when I run a unit test, but it doesn't work as intended. Here's the output:
Copy code
> Task :ccwsmodule:cleanIosX64Test UP-TO-DATE
> Task :ccwsmodule:compileKotlinIosX64
w: /Users/dana.haukoos/ClearCaptionsGit/KMMApplication/ccwsmodule/src/iosMain/kotlin/com/example/ccwsmodule/CCWSv2.kt: (14, 56): This cast can never succeed
> Task :ccwsmodule:iosX64ProcessResources NO-SOURCE
> Task :ccwsmodule:iosX64MainKlibrary
> Task :ccwsmodule:compileTestKotlinIosX64
> Task :ccwsmodule:linkDebugTestIosX64
> Task :ccwsmodule:iosX64Test
2020-10-26 23:22:51.814 simctl[18263:5286149] Unable to locate a bundle at URL file:///Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone%2012%20Pro%20Max.simdevicetype/
2020-10-26 23:22:51.814 simctl[18263:5286149] Unable to locate a bundle at URL file:///Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/
The url is <https://our.domain.com/user/get>
The postString is data={"email":"<mailto:dana.haukoos@clearcaptions.com|dana.haukoos@clearcaptions.com>"}
The response is The result is: None
BUILD SUCCESSFUL in 31s
5 actionable tasks: 4 executed, 1 up-to-date
11:22:52 PM: Tasks execution finished 'cleanIosX64Test iosX64Test --tests "com.example.ccwsmodule.ExampleUnitTest.test_getUser"'
I've noticed the warning:
Copy code
w: /Users/dana.haukoos/ClearCaptionsGit/KMMApplication/ccwsmodule/src/iosMain/kotlin/com/example/ccwsmodule/CCWSv2.kt: (14, 56): This cast can never succeed
but haven't figured out how to resolve it, and I'm not clear on it's impact. Obviously, none of the println statements in task callback are run - I'm not clear on how the async aspect is supposed to work.
r

russhwolf

10/27/2020, 1:31 PM
I think that warning (on casting String to NSString) is a false positive. We see the cast succeed or else the postString print wouldn’t work.
Since we see “The response is The result is: None” in the logs, I think you are hitting the callback but not getting data. Is the url correct? Does the same request work in an external tool like Postman? Does the equivalent code work if you write the same request in Swift?
d

Dana Haukoos

10/27/2020, 1:33 PM
I replaced the url with dummy data in my post, but the real url is working on the Android side.
The reason I think the callback isn't working is that I never see the output from the line
Copy code
println("The data is: " + result)
r

russhwolf

10/27/2020, 1:38 PM
I think it’s getting an empty string back, or you’d see the print as “The data is: null”.
not 100% sure on that though
d

Dana Haukoos

10/27/2020, 1:43 PM
I just added a simple println("Hello world") inside the callback and ran it, but that's not in the output. Isn't that a good test that the callback is [not] executed? The other question I had on that, though, is around async timing...if it gets called but not returned before the test ends.
(I tried adding an NSThread.sleep() to test that idea, but it created other issues, so I bailed on that exploration.)
r

russhwolf

10/27/2020, 1:46 PM
I would have expected the
task.resume()
to handle that
d

Dana Haukoos

10/27/2020, 1:46 PM
ok, yea that makes sense.
Does my statement about the println("Hello world") test make sense?
r

russhwolf

10/27/2020, 1:49 PM
ok yes. I was confusing the “the result is” line with the “the data is” print
d

Dana Haukoos

10/27/2020, 1:50 PM
(Yea, that is a bit confusing)
r

russhwolf

10/27/2020, 1:50 PM
Either way I think
nsData.toString()
won’t work the way you’re using it. You’ll need to convert the bytes explicitly, something like
result = nsData?.bytes?.reinterpret<ByteVar>()?.toKString() ?: ""
And now I’m seeing that yeah, your result string is never updating. You initialize it to “none” and that’s what prints
d

Dana Haukoos

10/27/2020, 1:53 PM
Yea, I realized the nsData.toString() was bogus, but I hadn't figured out the right way (thanks)
r

russhwolf

10/27/2020, 1:54 PM
I don’t have the NSURLSession APIs fresh enough in my head to really see what’s going wrong. I think my next step would be to try the same code in Swift so you have a comparison point
d

Dana Haukoos

10/27/2020, 1:54 PM
r

russhwolf

10/27/2020, 1:55 PM
Try
import kotlinx.cinterop.*
if they’re not auto-importing
d

Dana Haukoos

10/27/2020, 1:55 PM
That fixed that, thanks
On the Swift comparison side, I've tried that with different, yet not successful results. (The irony is I grabbed code out of our working application. I'm using a Swift playground as my testbed, so I'm not sure if that's part of my problem somehow...) Here's that code: var request = URLRequest(url: URL(string: "https://\(hostToUse)/user/get")!) request.setValue("close", forHTTPHeaderField: "Connection") request.httpMethod = "POST" request.timeoutInterval = 120.0 let postString = "data={\"email\":\"\(email)\"}" print("**Service Post : GetUser** =\(postString)") request.httpBody = postString.data(using: .utf8) let task = URLSession.shared.dataTask(with: request) { data, response, error in   guard let data = data, error == nil else {     print("errorInGetUser=\(String(describing: error))")     print("postString=\(postString)")     //completion(false, nil )     return   }   if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {     print("statusCode should be 200, but is (httpStatus.statusCode)")     //print("response = \(response)")   }   if let body_response = String(data: data, encoding: String.Encoding.utf8) {     print(body_response)   } } task.resume() At least I'm getting an error, but I haven't figured out the root issue: errorInGetUser=Optional(Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x600000645950 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=8, _kCFStreamErrorDomainKey=12}}, NSErrorFailingURLStringKey=https://our.domain.com/user/get, NSErrorFailingURLKey=https://our.domain.com/user/get, _kCFStreamErrorDomainKey=12, _kCFStreamErrorCodeKey=8, NSLocalizedDescription=A server with the specified hostname could not be found.})\n"
Googling on the error message Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." did not lead me to any resolution.
Do you think running this code in a Swift playground is somehow possibly related to why I'm getting this error?
r

russhwolf

10/27/2020, 2:24 PM
Maybe. Give it a try on a device or in the simulator instead and see if that helps
👍 1
d

Dana Haukoos

10/27/2020, 2:33 PM
Hmm, get the same error in the simulator.
r

russhwolf

10/27/2020, 2:35 PM
I'm not sure then. I guess try to dig into what's different between your app and this sample. Maybe a missing header or something that Android is adding and iOS isn't.
d

Dana Haukoos

10/27/2020, 2:37 PM
Yea, that's about all I can think to do too, thanks.
Well, I found I had a typo in the URL for my test case in Swift, so that's working now, at least.
Unfortunately, it doesn't add any insight to my KMM iOS issue, but it's still helpful to know that is working now.
r

russhwolf

10/27/2020, 4:35 PM
So there's no chance you made a similar type on the Kotlin version? Anything else obviously different between them?
d

Dana Haukoos

10/27/2020, 4:36 PM
I haven't found anything yet. In fact, the Kotlin IOS code is very close to the now validated swift code.
It occurs to me that I have no evidence that the server is even getting the http call...
r

russhwolf

10/27/2020, 4:39 PM
Have you tried the Kotlin code in an app instead of a unit test? That would eliminate the possibility that the callback is running after the test completes.
d

Dana Haukoos

10/27/2020, 4:42 PM
No, I haven't, which brings me back to a different issue. I realize I just sidestepped a build problem I mentioned before. You suggested this gradle addition:
Copy code
android {
    // ...
    packagingOptions {
        exclude("META_INF/*")
    }
}
(edited) but when I added that, it didn't resolve my problem:
A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > More than one file was found with OS independent path 'META-INF/DEPENDENCIES'.
I like your suggestion of trying this. Any further ideas what to look into on my issue building this module?
r

russhwolf

10/27/2020, 5:19 PM
oh oops I told you META_INF and it should have been META-INF
sorry about that
d

Dana Haukoos

10/27/2020, 5:24 PM
Ok, made that change, but still getting the error. To double check, this is in the build.gradle file for the ":shared" module, which is the app itself, correct?
r

russhwolf

10/27/2020, 5:25 PM
it'll depend on which module is failing to build. The gradle output should tell you which task failed, and that will indicate the module
d

Dana Haukoos

10/27/2020, 5:32 PM
The error is indicating
Task androidAppmergeDebugJavaResource FAILED
so that implicates the ":shared" module, I would infer. But that's what I tried, so maybe I'm not following yet.
r

russhwolf

10/27/2020, 5:33 PM
"androidApp" is the module name there
d

Dana Haukoos

10/27/2020, 5:35 PM
Ah, now I'm following. And now it builds, thanks!
When I try to run the function from the Kotlin app, the app crashes. When trying the iOS version of the app, I get Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared com.example.ccwsmodule.CCWSv2.$getUser$lambda-0$FUNCTION_REFERENCE$0@20cca48 from other thread. Googling that tells me I have an issues with async thread management, but not sure the best way to deal with it. For what it's worth, here's how I'm calling the function in the main app at the moment:
Copy code
println("getUser is ${ccws.getUser(email, host)}")
When I next run the Android version of the app, I get: E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.kmmapplication.androidApp, PID: 4481 java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; or its superclasses (declaration of 'org.apache.http.conn.ssl.AllowAllHostnameVerifier' appears in /system/framework/framework.jar!classes3.dex) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:151) at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:977) at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:56) at com.example.ccwsmodule.CCWSv2.getUser(CCWSv2.kt:19) ...
r

russhwolf

10/27/2020, 7:30 PM
Not sure on the Android issue. Try a clean build
For the iOS issue, I guess the NSURLSession is crossing thread boundaries which means the completion handler lambda has to be frozen. And that means you can't have a mutable var for your result field. Try something like this
Copy code
val result = AtomicReference("None")
val completionHandler = { nsData: NSData?, nsURLResponse: NSURLResponse?, nsError: NSError? ->
    if (nsError != null) {
        val message =
            "The response is: " + nsURLResponse?.description() + ", error is: " + nsError.description()
        println(message)
    }
    result.value = nsData?.bytes?.reinterpret<ByteVar>()?.toKString() ?: ""
    println("The data is: " + result.value)
}.freeze()
val task =
    NSURLSession.sharedSession.dataTaskWithRequest(request, completionHandler)
task.resume()
return "The result is: " + result.value
d

Dana Haukoos

10/27/2020, 7:36 PM
Thanks, I'll try it. What's the coroutines import for AtomicReference & freeze ?
r

russhwolf

10/27/2020, 7:37 PM
they're both in the
kotlin.native.concurrent
package.
d

Dana Haukoos

10/27/2020, 7:38 PM
Does that need a build.gradle dependency also?
r

russhwolf

10/27/2020, 7:39 PM
no it's part of the stdlib
👍 1
d

Dana Haukoos

10/27/2020, 7:44 PM
With that, the iOS app runs, and the http service call succeeds! 😃
r

russhwolf

10/27/2020, 7:44 PM
woohoo!
👍 1
d

Dana Haukoos

10/27/2020, 7:50 PM
Curiously, the iOS unit test still doesn't work. Now back to the Android app side (where the unit test works, but the app crashes).
(A clean & build didn't resolve it)
r

russhwolf

10/27/2020, 7:52 PM
I'm guessing the iOS test issue goes back to the test finishing before the callback runs.
✔️ 1
Android issue sounds weird. AFAIK nothing should be accessing org.apache.http unless you set it up that way intentionally or are using a very very old device.
d

Dana Haukoos

10/27/2020, 7:57 PM
I did use apache.http.client libraries...
r

russhwolf

10/27/2020, 7:58 PM
are you importing a gradle dependency for them? If not they probably won't work
I thought you had that working previously though
d

Dana Haukoos

10/27/2020, 7:59 PM
Yea, I did add the gradle dependency for them. (They looked rather equivalent to the iOS side.) And yes, the unit test works on the Android side.
So I have no theory as to why the unit test succeeds, but the app that calls it dies inside the function.
r

russhwolf

10/27/2020, 8:03 PM
It sounds like the depedency isn't working. Since unit tests run on your local JVM they have access to the Apache APIs that aren't built-in on Android. Take another look at your prod config compared to this proof-of-concept and see if there's anything missing.
The good news is that's definitely just an Android-side issue so it should be solvable regardless of your KMM setup
d

Dana Haukoos

10/27/2020, 8:07 PM
I'm tracking with you for this part: It sounds like the depedency isn't working. Since unit tests run on your local JVM they have access to the Apache APIs that aren't built-in on Android. Not quite following when you suggest: Take another look at your prod config compared to this proof-of-concept and see if there's anything missing. What exactly do you mean by my "prod config"?
r

russhwolf

10/27/2020, 8:09 PM
I understood that you're copying some stuff for this proof-of-concept from your existing app. So take another look to see if anything is missing there
d

Dana Haukoos

10/27/2020, 8:09 PM
We only have an iOS app at this point.
r

russhwolf

10/27/2020, 8:09 PM
oh nevermind then
in that case I'd generally advise not using the apache client. Look at okhttp instead for Android web calls
d

Dana Haukoos

10/27/2020, 8:14 PM
Ok, but help me understand, don't the dependency libraries get "compiled into" the module we build?
r

russhwolf

10/27/2020, 8:15 PM
yeah. It should be possible to make apache work. It's not that typical though and you won't find many helpful examples
d

Dana Haukoos

10/27/2020, 8:23 PM
I'll try it, thanks.
So not having any success with the okhttp version. The app doesn't crash, but it returns "Exception is null" for this code:
Copy code
actual fun getUser(email: String, hostToUse: String): String {
        val client = OkHttpClient()

        val url = "https://$hostToUse/user/get"
        println("The url is " + url.toString())
        val postString = "data={\"email\":\"$email\"}"
        println("The postString is " + postString)

       // val body: RequestBody = create(json, JSON)

        val body: RequestBody = RequestBody.create(
           //MediaType.parse("application/json"), postString
            MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"), postString
        )
        val request: Request = Request.Builder()
            .url(url)
            .post(body)
            .build()

        val call: Call = client.newCall(request)
        return try {
            val response: Response = call.execute()
            response.body().toString()
        } catch (e: Exception) {
            "Exception is " + e.message
        }
    }
}
Ok, here's an Android version using okhttp that works in the unit test:
Copy code
actual fun getUser(email: String, hostToUse: String): String {
    //val client = OkHttpClient()

    val CLIENT_TIMEOUT_MILLIS: Long = 60000
    val client  = OkHttpClient.Builder()
        .connectTimeout(CLIENT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
        .writeTimeout(CLIENT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
        .readTimeout(CLIENT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
        .build()

    val url = "https://$hostToUse/user/get"
    println("The url is " + url.toString())
    val postString = "data={\"email\":\"$email\"}"
    println("The postString is " + postString)

   // val body: RequestBody = create(json, JSON)

    val body: RequestBody = RequestBody.create(
        //MediaType.parse("application/json"), postString
        MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"), postString
    )
    val request: Request = Request.Builder()
        .url(url)
        .post(body)
        .build()
    println("The request body is " + request.body())

    val call: Call = client.newCall(request)
    return try {
        val httpResponse: Response = call.execute()
        println("POST Response Status: " + httpResponse.code())
        println("POST Response Success: " + httpResponse.isSuccessful)
        println("POST Response contentLegnth: " + httpResponse.body()!!.contentLength())

        val reader = BufferedReader(
            InputStreamReader(
                httpResponse.body()!!.byteStream()
            )
        )
        var inputLine: String?
        val response = StringBuffer()
        while (reader.readLine().also { inputLine = it } != null) {
            response.append(inputLine)
        }
        reader.close()

        response.toString()
    } catch (e: Exception) {
        "Exception is " + e.message
    }
}
Still need to get it working when called via the app.
Here's a different question I have about my kmm module. I see the Android aar file in mymodule/build/outputs/aar/mymodule-debug.aar. But I don't see where to find the corresponding iOS build artifact?
r

russhwolf

10/28/2020, 3:19 PM
Hey sorry I missed this stuff yesterday. I'm guessing the Android issue is that it doesn't want you making web calls on the UI thread.
The iOS artifact will depend on your gradle setup. By default it will create a klib file which can be consumed by other kotlin projects. Probably you have some config based on the template you used that will also generate a framework.
Take a look inside
build/bin
in your shared module
d

Dana Haukoos

10/28/2020, 3:26 PM
Ok, inside build/bin I find /iosX64/test.kexe, test.kexe,dSYM
r

russhwolf

10/28/2020, 3:26 PM
that's the executable that runs the unit tests
✔️ 1
try a
./gradlew build
to build everything and probably there will be a framework in there too
d

Dana Haukoos

10/28/2020, 3:29 PM
ok, trying that
Task androidApplint
Ran lint on variant debug: 6 issues found Ran lint on variant release: 4 issues found Wrote HTML report to file:///Users/dana.haukoos/ClearCaptionsGit/KMMApplication/androidApp/build/reports/lint-results.html Wrote XML report to file:///Users/dana.haukoos/ClearCaptionsGit/KMMApplication/androidApp/build/reports/lint-results.xml Expiring Daemon because JVM heap space is exhausted Daemon will be stopped at the end of the build after running out of JVM memory Expiring Daemon because JVM heap space is exhausted Expiring Daemon because JVM heap space is exhausted Expiring Daemon because JVM heap space is exhausted Expiring Daemon because JVM heap space is exhausted Expiring Daemon because JVM heap space is exhausted Expiring Daemon because JVM heap space is exhausted
Task ccwsmodulelinkDebugTestIosX64 FAILED
e: /Users/dana.haukoos/ClearCaptionsGit/KMMApplication/ccwsmodule/src/iosTest/kotlin/com/example/ccwsmodule/iosTest.kt: Test function must return Unit: com.example.ccwsmodule.iOSUnitTest.test_getUser FAILURE: Build failed with an exception. * What went wrong: Execution failed for task 'ccwsmodulelinkDebugTestIosX64'.
Compilation finished with errors
* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 1m 54s 206 actionable tasks: 2 executed, 204 up-to-date Expiring Daemon because JVM heap space is exhausted
r

russhwolf

10/28/2020, 3:39 PM
Copy code
e: /Users/dana.haukoos/ClearCaptionsGit/KMMApplication/ccwsmodule/src/iosTest/kotlin/com/example/ccwsmodule/iosTest.kt: Test function must return Unit: com.example.ccwsmodule.iOSUnitTest.test_getUser
Fix this function
though, it probably got far enough to build the framework anyway if you're just looking for that
d

Dana Haukoos

10/28/2020, 3:42 PM
Ah, I see it did... build/bin/iosArm64/debugFramework/... and build/bin/iosX64/debugFramework/
(Also seeing if I've fixed the unit test.)
OK, so here's where I'm at: So on the iOS side, my function works in the iOS app, but not in the unit test. Conversely, on the Android side, my function works in the unit test, but not in the Android app. (To clarify, when I say it works, I mean I see the expected response data in my println() statements embedded in the function.)
Earlier we speculated that the iOS unit test didn't work due to the test ending before the function returned its data. Do you know of a simple async test example to test this hypothesis?
155 Views