Distribute Kotlin Library
Release A Library Using The Plugin
We can distribute to other users a Kotlin library using native or third-party dependency, some requirements are necessary for Apple targets.
Requirement
The user must :
- add the same native dependency used by the Kotlin library to his Xcode project.
- use the same version as the library use.
It will fix issues with linking, missing resources, App Store compliance, and more.
Note
The user doesn't have access to the Kotlin library source code, which is great!
Publish Safe
Set publishSafe = true on a library you publish, so its klibs don't embed the paths of the build machine (every consumer would get ld: warning: search path '...' not found).
The library's own binaries still link. A consumer linking with Gradle rather than Xcode must provide the native dependencies through linkerOpts.
Example
A Compose Multiplatform Component library using a native video player.
@Composable
public expect fun KmpPlayer(modifier: Modifier = Modifier, url: String)
Android
For Android, it uses Exoplayer.
Gradle
androidMain.dependencies {
implementation(libs.media3.exoplayer)
implementation(libs.media3.exoplayer.dash)
implementation(libs.media3.ui)
}
AndroidMain
@Composable
public actual fun KmpPlayer(modifier: Modifier, url: String) {
val context = LocalContext.current
// Initialize ExoPlayer
val exoPlayer = ExoPlayer.Builder(context).build()
val mediaSource = remember(url) {
MediaItem.fromUri(url)
}
LaunchedEffect(url) {
exoPlayer.setMediaItem(mediaSource)
exoPlayer.prepare()
}
// Manage lifecycle events
DisposableEffect(Unit) {
onDispose {
exoPlayer.release()
}
}
AndroidView(
factory = { ctx ->
PlayerView(ctx).apply {
player = exoPlayer
}
},
modifier = modifier
)
}
iOS
For iOS, it uses KSPlayer, it's a pure Swift library.
Gradle
kotlin {
iosArm64 {
swiftPackageConfig(cinteropName = "appleDeps") {
minIos = "13.0"
minMacos = "10.15"
minTvos = "13.0"
minWatchos = "2.0"
dependency {
remotePackageBranch(
url = URI("https://github.com/kingslay/KSPlayer"),
products = {
add("KSPlayer")
},
branch = "main"
)
}
}
}
}
Bridge
Some tips here.
import Foundation
import KSPlayer
@objcMembers public class MEPlayerController: NSObject {
private let player = IOSVideoPlayerView()
override init() {
super.init()
KSOptions.secondPlayerType = KSMEPlayer.self
player.delegate = self
player.autoresizingMask = [.flexibleWidth, .flexibleHeight]
player.contentMode = .scaleAspectFill
}
public func setMediaItem(videoUrl: URL) {
player.set(
url: videoUrl,
options: KSOptions()
)
}
public var playerView: NSObject {
player
}
public func releasePlayer() {
player.resetPlayer()
player.removeFromSuperview()
}
}
IOSMain
import appleDeps.MEPlayerController
@Composable
public actual fun KmpPlayer(modifier: Modifier, url: String) {
val playerController = MEPlayerController()
val mediaSource = remember(url) {
NSURL.URLWithString(url)
}
LaunchedEffect(url) {
if (mediaSource == null) {
throw Exception("Bad input URL")
}
playerController.setMediaItemWithVideoUrl(videoUrl = mediaSource)
}
DisposableEffect(Unit) {
onDispose {
playerController.releasePlayer()
}
}
UIKitView(
factory = {
playerController.playerView() as UIView
},
modifier = modifier,
update = {
}
)
}
Requirement
The setup guide of your library must contain the rule that KSPlayer package must be added to his Xcode project with the explicit version.
Sample
The sample is available.
- Run the command
./gradlew publishToMavenLocal --no-configuration-cacheon the repository root. - Open the project
sampleAppand test the application