Skip to content

Commit 12058c3

Browse files
authored
Add Android Native support (#599)
1 parent 0c29637 commit 12058c3

File tree

46 files changed

+744
-73
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+744
-73
lines changed

.github/workflows/CI.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
7070
- name: Upload Test Reports
7171
uses: actions/upload-artifact@v4
72-
if: ${{ always() }}
72+
if: always()
7373
with:
7474
name: test-report-${{ matrix.os }}-java${{ matrix.java-version }}
7575
path: '**/build/reports/tests/**'
@@ -106,12 +106,14 @@ jobs:
106106
emulator-boot-timeout: 300 # 5 minutes
107107
api-level: ${{ matrix.api-level }}
108108
arch: x86_64
109-
script: ./gradlew connectedCheck -PKMP_TARGETS="ANDROID,JVM"
109+
script: ./gradlew connectedCheck -PKMP_TARGETS="ANDROID,ANDROID_ARM32,ANDROID_ARM64,ANDROID_X64,ANDROID_X86,JVM"
110110

111111
- name: Upload Test Reports
112112
uses: actions/upload-artifact@v4
113-
if: ${{ always() }}
113+
if: always()
114114
with:
115115
name: test-report-android-${{ matrix.api-level }}
116-
path: '**/build/reports/androidTests/**'
116+
path: |
117+
**/build/reports/androidTests/**
118+
**/build/outputs/androidTest-results/connected/debug/*/logcat-*.txt
117119
retention-days: 1

build-logic/src/main/kotlin/-KmpConfigurationExtension.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ fun KmpConfigurationExtension.configureShared(
6565
}
6666
}
6767

68+
androidNativeAll()
6869
iosAll()
6970
linuxAll()
7071
macosAll()

gradle/libs.versions.toml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ kotlincrypto-catalog = "0.7.1" # Utilized from settings.gradle.kts
3030
kotlinx-coroutines = "1.10.2"
3131
ktor = "3.1.3"
3232

33-
okio = "3.11.0"
34-
3533
[libraries]
3634
androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup" }
3735

@@ -61,15 +59,13 @@ bouncy-castle = { module = "org.bouncycastle:bcprov-jdk18on", vers
6159

6260
jetbrains-skiko = { module = "org.jetbrains.skiko:skiko-awt", version.ref = "jetbrains-skiko" }
6361

62+
kmp-tor-resource-android-unit-test-tor = { module = "io.matthewnelson.kmp-tor:resource-android-unit-test-tor", version.ref = "kmp-tor-resource" }
63+
kmp-tor-resource-compilation-exec-tor = { module = "io.matthewnelson.kmp-tor:resource-compilation-exec-tor", version.ref = "kmp-tor-resource" }
6464
kmp-tor-resource-exec-tor = { module = "io.matthewnelson.kmp-tor:resource-exec-tor", version.ref = "kmp-tor-resource" }
6565
kmp-tor-resource-noexec-tor = { module = "io.matthewnelson.kmp-tor:resource-noexec-tor", version.ref = "kmp-tor-resource" }
66-
kmp-tor-resource-android-unit-test-tor = { module = "io.matthewnelson.kmp-tor:resource-android-unit-test-tor", version.ref = "kmp-tor-resource" }
6766
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
6867
ktor-network = { module = "io.ktor:ktor-network", version.ref = "ktor" }
6968

70-
okio-okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
71-
okio-node = { module = "com.squareup.okio:okio-nodefilesystem", version.ref = "okio" }
72-
7369
[plugins]
7470
android-library = { id = "com.android.library", version.ref = "gradle-android" }
7571
binary-compat = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "gradle-binary-compat" }

library/runtime-core/api/runtime-core.klib.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Klib ABI Dump
2-
// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64]
3-
// Alias: native => [iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64]
2+
// Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64]
3+
// Alias: native => [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64]
44
// Rendering settings:
55
// - Signature version: 2
66
// - Show manifest properties: true

library/runtime-core/build.gradle.kts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
**/
16+
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
17+
import org.jetbrains.kotlin.konan.target.Family
18+
1619
plugins {
1720
id("configuration")
1821
}
@@ -87,5 +90,32 @@ kmpConfiguration {
8790
}
8891
}
8992
}
93+
94+
kotlin {
95+
val cInteropDir = projectDir
96+
.resolve("src")
97+
.resolve("nativeInterop")
98+
.resolve("cinterop")
99+
100+
targets.filterIsInstance<KotlinNativeTarget>().forEach target@ { target ->
101+
when (target.konanTarget.family) {
102+
Family.ANDROID, Family.IOS, Family.TVOS, Family.WATCHOS -> {}
103+
else -> return@target
104+
}
105+
106+
target.compilations["main"].cinterops.create("network") {
107+
definitionFile.set(cInteropDir.resolve("$name.def"))
108+
}
109+
}
110+
111+
project.afterEvaluate {
112+
val commonizeTask = project.tasks.findByName("commonizeCInterop") ?: return@afterEvaluate
113+
114+
project.tasks.all {
115+
if (!name.endsWith("MetadataElements")) return@all
116+
dependsOn(commonizeTask)
117+
}
118+
}
119+
}
90120
}
91121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
@file:Suppress("KotlinRedundantDiagnosticSuppress", "FunctionName")
17+
18+
package io.matthewnelson.kmp.tor.runtime.core.internal
19+
20+
import kotlinx.cinterop.ByteVar
21+
import kotlinx.cinterop.CPointer
22+
import kotlinx.cinterop.CValuesRef
23+
import kotlinx.cinterop.ExperimentalForeignApi
24+
import kotlinx.cinterop.UnsafeNumber
25+
import kotlinx.cinterop.convert
26+
import platform.posix.socklen_t
27+
28+
@Suppress("NOTHING_TO_INLINE")
29+
@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
30+
internal actual inline fun platform_inet_ntop(
31+
family: Int,
32+
src: CValuesRef<*>?,
33+
dst: CValuesRef<ByteVar>?,
34+
size: socklen_t,
35+
): CPointer<ByteVar>? = inet_ntop(family, src, dst, size.convert())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
@file:Suppress("KotlinRedundantDiagnosticSuppress", "FunctionName")
17+
18+
package io.matthewnelson.kmp.tor.runtime.core.internal
19+
20+
import kotlinx.cinterop.ByteVar
21+
import kotlinx.cinterop.CPointer
22+
import kotlinx.cinterop.CValuesRef
23+
import kotlinx.cinterop.ExperimentalForeignApi
24+
import kotlinx.cinterop.UnsafeNumber
25+
import kotlinx.cinterop.convert
26+
import platform.posix.socklen_t
27+
28+
@Suppress("NOTHING_TO_INLINE")
29+
@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
30+
internal actual inline fun platform_inet_ntop(
31+
family: Int,
32+
src: CValuesRef<*>?,
33+
dst: CValuesRef<ByteVar>?,
34+
size: socklen_t,
35+
): CPointer<ByteVar>? = inet_ntop(family, src, dst, size.convert())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
package io.matthewnelson.kmp.tor.runtime.core.internal
17+
18+
import kotlinx.cinterop.ExperimentalForeignApi
19+
20+
@OptIn(ExperimentalForeignApi::class)
21+
internal actual val AFUnixPathBufSize: Int = UNIX_PATH_MAX
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
17+
18+
package io.matthewnelson.kmp.tor.runtime.core
19+
20+
actual class OnEventExecutorUnitTest: OnEventExecutorBaseTest() {
21+
override val expectedIsAvailable: Boolean = false
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
@file:Suppress("KotlinRedundantDiagnosticSuppress", "FunctionName")
17+
18+
package io.matthewnelson.kmp.tor.runtime.core.internal
19+
20+
import kotlinx.cinterop.ByteVar
21+
import kotlinx.cinterop.CPointer
22+
import kotlinx.cinterop.CValuesRef
23+
import kotlinx.cinterop.ExperimentalForeignApi
24+
import kotlinx.cinterop.UnsafeNumber
25+
import kotlinx.cinterop.convert
26+
import platform.posix.socklen_t
27+
28+
@Suppress("NOTHING_TO_INLINE")
29+
@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
30+
internal actual inline fun platform_inet_ntop(
31+
family: Int,
32+
src: CValuesRef<*>?,
33+
dst: CValuesRef<ByteVar>?,
34+
size: socklen_t,
35+
): CPointer<ByteVar>? = inet_ntop(family, src, dst, size.convert())

0 commit comments

Comments
 (0)