集成 Timber 日志框架,降级 AGP/Gradle 适配 JDK 17,修复构建设置

- 新增 PosefitApplication 初始化 Timber DebugTree

- WebRtcSenderClient/MainActivity/SimpleSdpObserver 添加 Timber 日志

- AGP 9.2.1 → 8.7.3,Gradle 9.4.1 → 8.11.1 适配 JDK 17

- compileSdk/targetSdk 恢复为 34,minSdk 保持 29 支持 Android 10

- 添加 android.useAndroidX=true 修复构建检查

- 删除 gradle-daemon-jvm.properties (JDK 21 残留配置)

- 信令端口默认改为 8765
This commit is contained in:
2026-06-01 23:50:57 +08:00
parent 334df75155
commit a355919cdc
11 changed files with 81 additions and 25 deletions
+2
View File
@@ -29,6 +29,7 @@ android {
}
buildFeatures {
compose true
buildConfig true
}
}
@@ -47,6 +48,7 @@ dependencies {
testImplementation libs.junit
androidTestImplementation libs.espresso.core
androidTestImplementation libs.ext.junit
implementation libs.timber
implementation "io.getstream:stream-webrtc-android:1.3.10"
implementation "com.squareup.okhttp3:okhttp:4.12.0"
}
+1
View File
@@ -19,6 +19,7 @@
android:required="true" />
<application
android:name=".PosefitApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.kimgo.posefit.sender.WebRtcSenderClient
import timber.log.Timber
class MainActivity : ComponentActivity() {
@@ -23,11 +24,14 @@ class MainActivity : ComponentActivity() {
if (granted) {
val url = getSavedSignalingUrl()
startWebRtc(url)
} else {
Timber.w("Camera permission denied")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.d("MainActivity onCreate")
setContent {
MaterialTheme {
@@ -87,7 +91,7 @@ class MainActivity : ComponentActivity() {
private fun getSavedSignalingUrl(): String {
val prefs = getSharedPreferences("posefit_prefs", Context.MODE_PRIVATE)
return prefs.getString("signaling_url", "ws://192.168.110.240:8080") ?: "ws://192.168.110.240:8080"
return prefs.getString("signaling_url", "ws://192.168.2.10:8765") ?: "ws://192.168.2.10:8765"
}
private fun saveSignalingUrl(url: String) {
@@ -96,6 +100,7 @@ class MainActivity : ComponentActivity() {
}
private fun startWebRtc(url: String) {
Timber.i("startWebRtc: %s", url)
webRtcClient?.release()
webRtcClient = WebRtcSenderClient(
context = this,
@@ -105,6 +110,7 @@ class MainActivity : ComponentActivity() {
}
private fun stopWebRtc() {
Timber.i("stopWebRtc")
webRtcClient?.release()
webRtcClient = null
}
@@ -112,5 +118,6 @@ class MainActivity : ComponentActivity() {
override fun onDestroy() {
super.onDestroy()
stopWebRtc()
Timber.d("MainActivity onDestroy")
}
}
@@ -0,0 +1,13 @@
package com.kimgo.posefit
import android.app.Application
import timber.log.Timber
class PosefitApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
}
}
@@ -2,11 +2,16 @@ package com.kimgo.posefit.sender
import org.webrtc.SdpObserver
import org.webrtc.SessionDescription
import timber.log.Timber
open class SimpleSdpObserver : SdpObserver {
override fun onCreateSuccess(desc: SessionDescription) {}
override fun onSetSuccess() {}
override fun onCreateFailure(error: String) {}
override fun onSetFailure(error: String) {}
override fun onCreateFailure(error: String) {
Timber.e("SDP onCreateFailure: %s", error)
}
override fun onSetFailure(error: String) {
Timber.e("SDP onSetFailure: %s", error)
}
}
@@ -4,6 +4,7 @@ import android.content.Context
import okhttp3.*
import org.json.JSONObject
import org.webrtc.*
import timber.log.Timber
class WebRtcSenderClient(
private val context: Context,
@@ -23,6 +24,7 @@ class WebRtcSenderClient(
private var surfaceTextureHelper: SurfaceTextureHelper? = null
fun start() {
Timber.i("WebRTC starting, signalingUrl=%s", signalingUrl)
initPeerConnectionFactory()
connectSignaling()
}
@@ -47,6 +49,8 @@ class WebRtcSenderClient(
.setVideoEncoderFactory(encoderFactory)
.setVideoDecoderFactory(decoderFactory)
.createPeerConnectionFactory()
Timber.d("PeerConnectionFactory initialized")
}
private fun connectSignaling() {
@@ -57,6 +61,7 @@ class WebRtcSenderClient(
webSocket = okHttpClient.newWebSocket(request, object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
Timber.d("Signaling WebSocket connected")
createPeerConnection()
startCamera()
createOffer()
@@ -65,6 +70,14 @@ class WebRtcSenderClient(
override fun onMessage(webSocket: WebSocket, text: String) {
handleSignalingMessage(text)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Timber.e(t, "Signaling WebSocket failure")
}
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
Timber.w("Signaling WebSocket closed, code=%d, reason=%s", code, reason)
}
})
}
@@ -93,10 +106,16 @@ class WebRtcSenderClient(
webSocket.send(json.toString())
}
override fun onIceConnectionChange(state: PeerConnection.IceConnectionState) {
Timber.d("ICE connection state: %s", state)
}
override fun onIceGatheringChange(state: PeerConnection.IceGatheringState) {
Timber.d("ICE gathering state: %s", state)
}
override fun onSignalingChange(state: PeerConnection.SignalingState) {}
override fun onIceConnectionChange(state: PeerConnection.IceConnectionState) {}
override fun onIceConnectionReceivingChange(receiving: Boolean) {}
override fun onIceGatheringChange(state: PeerConnection.IceGatheringState) {}
override fun onIceCandidatesRemoved(candidates: Array<out IceCandidate>) {}
override fun onAddStream(stream: MediaStream) {}
override fun onRemoveStream(stream: MediaStream) {}
@@ -137,6 +156,8 @@ class WebRtcSenderClient(
videoTrack,
listOf("posefit_stream")
)
Timber.d("Camera started: %s, resolution=1280x720@30fps", cameraName)
}
private fun createOffer() {
@@ -160,17 +181,27 @@ class WebRtcSenderClient(
}
webSocket.send(json.toString())
Timber.d("Offer sent via signaling")
}
override fun onSetFailure(error: String) {
Timber.e("setLocalDescription failed: %s", error)
}
override fun onSetFailure(error: String) {}
override fun onCreateSuccess(desc: SessionDescription) {}
override fun onCreateFailure(error: String) {}
override fun onCreateFailure(error: String) {
Timber.e("createOffer failed: %s", error)
}
}, desc)
}
override fun onSetSuccess() {}
override fun onCreateFailure(error: String) {}
override fun onSetFailure(error: String) {}
override fun onCreateFailure(error: String) {
Timber.e("createOffer failed: %s", error)
}
override fun onSetFailure(error: String) {
Timber.e("setLocalDescription failed: %s", error)
}
}, constraints)
}
@@ -189,6 +220,7 @@ class WebRtcSenderClient(
SimpleSdpObserver(),
sdp
)
Timber.d("Answer received from server")
}
"candidate" -> {
@@ -204,6 +236,8 @@ class WebRtcSenderClient(
}
fun release() {
Timber.i("WebRTC releasing")
try {
videoCapturer?.stopCapture()
} catch (_: Exception) {
@@ -219,5 +253,7 @@ class WebRtcSenderClient(
eglBase.release()
webSocket.close(1000, "close")
okHttpClient.dispatcher.executorService.shutdown()
Timber.d("WebRTC released")
}
}
+1
View File
@@ -1,4 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
}
+2
View File
@@ -7,6 +7,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.java.home=C\:\\Program Files\\Java\\jdk-17
android.useAndroidX=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
-12
View File
@@ -1,12 +0,0 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect
toolchainVersion=21
+3 -1
View File
@@ -1,5 +1,5 @@
[versions]
agp = "9.2.1"
agp = "8.7.3"
kotlin = "2.0.0"
composeBom = "2024.02.00"
composeCompiler = "1.5.8"
@@ -11,8 +11,10 @@ junitVersion = "1.1.5"
espressoCore = "3.5.1"
appcompat = "1.6.1"
material = "1.10.0"
timber = "5.0.1"
[libraries]
timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+2 -3
View File
@@ -1,9 +1,8 @@
#Mon Jun 01 17:35:27 CST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
validateDistributionUrl=false
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists