Files
2026-07-14 11:11:36 +08:00

155 lines
6.1 KiB
Kotlin
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Media3 Engine plugin — Android-only ExoPlayer + FFmpeg audio decoder bridge.
//
// 依赖:
// - Maven Central: media3-exoplayer / media3-datasource / media3-decoder 1.10.1
// - 本地 AAR : media3-decoder-ffmpeg-1.10.1-arm64.aar
// 由 fileTree 从主 app 的 android/app/libs/ 加载。AAR 由
// scripts/build_media3_ffmpeg.sh 自编译产出,CHECKSUMS.txt
// 记录 SHA-256。
//
// AAR 缺失时 preBuild 任务会 fail-fast 抛出带恢复指引的错误(详见 README)。
import java.security.MessageDigest
plugins {
id("com.android.library")
id("kotlin-android")
}
group = "com.smplayer.media3_engine"
version = "0.0.1"
android {
namespace = "com.smplayer.media3_engine"
compileSdk = 36
defaultConfig {
minSdk = 24
ndk {
// 与主 app 保持一致:仅 arm64-v8a。其它 ABI 在 FFmpeg AAR 中也不存在,
// 即便 ABI filter 漏了也只是无声的浪费(不会 crash)。
abiFilters += listOf("arm64-v8a")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
buildFeatures {
buildConfig = false
}
}
repositories {
google()
mavenCentral()
}
// 自编译 FFmpeg audio decoder extensionarm64-v8a onlyLGPL 配置)。AAR 由
// scripts/build_media3_ffmpeg.sh 产出,放在 android/app/libs/。
// 这里只声明 compileOnlyAGP 8 起禁止 library module 直接 implementation 本地
// .aar"Direct local .aar file dependencies are not supported when building an
// AAR"),实际把 AAR 打入最终 APK 的责任落到主 app/build.gradle.kts 的
// `implementation(fileTree("libs"))`。本 plugin 编译期只需要 FfmpegAudioRenderer
// 等符号的可见性。
val media3Version = "1.10.1"
val ffmpegAarDir = file("../../../android/app/libs")
val ffmpegAarName = "media3-decoder-ffmpeg-$media3Version-arm64.aar"
dependencies {
implementation("androidx.media3:media3-exoplayer:$media3Version")
implementation("androidx.media3:media3-datasource:$media3Version")
implementation("androidx.media3:media3-decoder:$media3Version")
implementation("androidx.media3:media3-ui:$media3Version")
compileOnly(fileTree(mapOf("dir" to ffmpegAarDir, "include" to listOf(ffmpegAarName))))
}
// AAR 缺失 / 篡改 fail-fast:在 preBuild 之前校验文件存在性 + SHA-256 与
// `android/app/libs/CHECKSUMS.txt` 一致。CI/Clean checkout 友好。
val verifyMedia3FfmpegAar by tasks.registering {
group = "verification"
description = "Verify media3 FFmpeg decoder AAR exists and matches CHECKSUMS.txt."
val checksumsFile = ffmpegAarDir.resolve("CHECKSUMS.txt")
val aarFile = ffmpegAarDir.resolve(ffmpegAarName)
inputs.file(aarFile).withPropertyName("aar").withPathSensitivity(org.gradle.api.tasks.PathSensitivity.NONE)
inputs.file(checksumsFile).withPropertyName("checksums").withPathSensitivity(org.gradle.api.tasks.PathSensitivity.NONE)
doLast {
if (!aarFile.isFile) {
throw GradleException(
"""
|Media3 FFmpeg decoder AAR is missing:
| expected: ${aarFile.absolutePath}
|
|This AAR is self-built (LGPL config, arm64-v8a,
|codecs: dca/ac3/eac3/truehd/opus/vorbis/flac).
|To produce it, run from the repo root:
|
| scripts/build_media3_ffmpeg.sh
|
|Prerequisites: NDK r26b, JDK 17, ~30-60min wall-clock. See
|plugins/media3_engine/README.md for full instructions and Docker recipe.
|
|If you only build the desktop (Windows/macOS) target, this Android
|module is not on the dependency path and you can ignore this error.
""".trimMargin()
)
}
if (!checksumsFile.isFile) {
throw GradleException(
"Media3 AAR checksum manifest is missing: ${checksumsFile.absolutePath}\n" +
"Restore CHECKSUMS.txt from git or rerun scripts/build_media3_ffmpeg.sh."
)
}
// CHECKSUMS.txt 行格式:`<sha256> <filename>`,可有 # 开头注释 / 空行
val expectedSha = checksumsFile.readLines()
.map { it.trim() }
.firstOrNull { it.isNotEmpty() && !it.startsWith("#") && it.endsWith(ffmpegAarName) }
?.substringBefore(' ')
?.trim()
?.lowercase()
if (expectedSha.isNullOrBlank() || !expectedSha.matches(Regex("^[0-9a-f]{64}$"))) {
throw GradleException(
"Media3 AAR checksum entry missing or malformed for $ffmpegAarName in " +
"${checksumsFile.absolutePath}. Expected a line: '<sha256> $ffmpegAarName'."
)
}
val md = MessageDigest.getInstance("SHA-256")
aarFile.inputStream().use { input ->
val buffer = ByteArray(8192)
while (true) {
val n = input.read(buffer)
if (n <= 0) break
md.update(buffer, 0, n)
}
}
val actualSha = md.digest().joinToString("") { "%02x".format(it) }
if (actualSha != expectedSha) {
throw GradleException(
"""
|Media3 FFmpeg decoder AAR checksum mismatch — refusing to build.
| file : ${aarFile.absolutePath}
| expected : $expectedSha (from CHECKSUMS.txt)
| actual : $actualSha
|
|The AAR has been replaced/corrupted since CHECKSUMS.txt was written.
|If you intentionally rebuilt it, scripts/build_media3_ffmpeg.sh will
|refresh CHECKSUMS.txt automatically; otherwise restore the file from git.
""".trimMargin()
)
}
logger.lifecycle("[verifyMedia3FfmpegAar] OK — sha256 $actualSha")
}
}
afterEvaluate {
tasks.named("preBuild").configure {
dependsOn(verifyMedia3FfmpegAar)
}
}