A multiplatform solution to use Python with Kotlin interoperably.
Thanks to many contributors who develop dependent packages for this python-kotlin library production.
- Android (arm64, arm32, x86, x86_64) with Kivy Android ToolChain
- iOS (arm64) with Kivy ios Toolchain
- masOS (universal) with Python Standalone Builds
- Linux (x86_64) with Python Standalone Builds
- Windows (x86_64) with Python Standalone Builds
- WASM - Not yet supported.
Note
** Since Xcode only runs on macOS, you need macOS to build this repo for iOS.
- Bring python embed API for Kotlin/JVM targets (Windows, Linux, macOS, Android).
- Bring python embed API for Kotlin/Native targets (iOS).
- Python interop API (Binder) for Kotlin side.
- Kotlin interop API (Binder) for Python side.
RC version
git clone https://github.com/thisisthepy/python-multiplatform-mobile PythonMultiplatformMobile
dev version
git clone https://github.com/thisisthepy/python-multiplatform-mobile@develop PythonMultiplatformMobile
specific release version
git clone https://github.com/thisisthepy/python-multiplatform-mobile@python3.13 PythonMultiplatformMobile
This is a Kotlin Multiplatform project targeting Android, iOS, Web, Desktop.
/composeAppis for code that will be shared across your Compose Multiplatform applications. It contains several subfolders:commonMainis for code that’s common for all targets.- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
iosMainwould be the right folder for such calls.
/iosAppcontains iOS applications. Even if you’re sharing your UI with Compose Multiplatform, you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
Learn more about Kotlin Multiplatform, Compose Multiplatform, Kotlin/Wasm…
We would appreciate your feedback on Compose/Web and Kotlin/Wasm in the public Slack channel #compose-web. If you face any issues, please report them on GitHub.
You can open the web application by running the :composeApp:wasmJsBrowserDevelopmentRun Gradle task.
In your project build.gradle.kts
implementation("io.github.thisisthepy:python-multiplatform:0.0.1")
In your project settings.gradle.kts
pluginManagement {
repositories {
google {
mavenContent {
includeGroupAndSubgroups("androidx")
includeGroupAndSubgroups("com.android")
includeGroupAndSubgroups("com.google")
}
}
mavenCentral()
gradlePluginPortal()
maven {
setUrl("https://jitpack.io") // Add this line!
}
}
}
In your project build.gradle.kts
implementation("com.github.thisisthepy:python-multiplatform-mobile:0.0.1")
Tip
Some tips
In your main method,
object PythonIntegration {
val python =Python3Library()
@JvmStatic
funmain(args:Array<String>) {
python!!.Py_Initialize() // Run python interprepterif (python!!.Py_IsInitialized() ==0) {
throwRuntimeException("Failed to initialize Python")
}
val module = py!!.PyImport_ImportModule(moduleName) // Module importif (module ==null) {
throwRuntimeException("Failed to import module: $moduleName")
}
callFunction(mathModule, "pow", 2.0, 3.0)
val func = py!!.PyObject_GetAttrString(module, funcName)
if (func ==null) {
throw java.lang.RuntimeException("Failed to get function: $funcName")
}
val pyArgs = py!!.PyTuple_New(args.size)
for (i in args.indices) {
val arg = convertJavaToPython(args[i])
println("The type of variable is ${arg::class.simpleName}")
py!!.PyTuple_SetItem(pyArgs, i, arg)
}
val result = py!!.PyObject_CallObject(func, pyArgs)
if (result !=null) {
println(funcName +" result: "+ convertPythonToJava(result))
py!!.Py_DecRef(result)
}
py!!.Py_DecRef(pyArgs)
py!!.Py_DecRef(func)
python!!.Py_DecRef(mathModule)
if (python!!.Py_IsInitialized() !=0) {
python!!.Py_Finalize()
}
}
privatefunconvertJavaToPython(obj:Any): Pointer {
if (obj isInt|| obj isLong) {
println("obj is converted to PyLong: $obj")
return py!!.PyLong_FromLong((obj asNumber).toLong())
} elseif (obj isFloat|| obj isDouble) {
println("obj is converted to PyFloat: $obj")
return py!!.PyFloat_FromDouble((obj asNumber).toDouble())
} elseif (obj isString) {
println("obj is converted to String: $obj")
return py!!.PyUnicode_FromString(obj)
}
throwUnsupportedOperationException("Unsupported type: "+ obj.javaClass)
}
privatefunconvertPythonToJava(pyObj:Pointer): Any {
// This is a simplistic conversion. In a real-world scenario, you'd need more type checking.val result1 = py!!.PyLong_AsLong(pyObj)
if (py!!.PyErr_Occurred() ==null) {
return result1
}
py!!.PyErr_Clear()
val result2 = py!!.PyFloat_AsDouble(pyObj)
if (py!!.PyErr_Occurred() ==null) {
return result2
}
py!!.PyErr_Clear()
val result3 = py!!.PyUnicode_AsUTF8(pyObj)
if (py!!.PyErr_Occurred() ==null) {
return result3
}
py!!.PyErr_Clear()
throwUnsupportedOperationException("Unsupported type")
}
}
Important
Somethig important