添加前台播放服务以支持直播播放,更新相关权限和通知逻辑
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
@@ -75,6 +76,11 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:foregroundServiceType="camera|microphone|mediaProjection" />
|
android:foregroundServiceType="camera|microphone|mediaProjection" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".live.LivePlayForegroundService"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="mediaPlayback" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ class LivePlayActivity : AppCompatActivity() {
|
|||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
logEvent("用户操作: 暂停")
|
logEvent("用户操作: 暂停")
|
||||||
playerClient.pause()
|
playerClient.pause()
|
||||||
|
stopPlaybackForegroundService()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logEvent("用户操作: 播放")
|
logEvent("用户操作: 播放")
|
||||||
@@ -272,6 +273,7 @@ class LivePlayActivity : AppCompatActivity() {
|
|||||||
if (hasReleasedPlayer) return
|
if (hasReleasedPlayer) return
|
||||||
hasReleasedPlayer = true
|
hasReleasedPlayer = true
|
||||||
playerClient.release()
|
playerClient.release()
|
||||||
|
stopPlaybackForegroundService()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun finishForNewPlayback() {
|
private fun finishForNewPlayback() {
|
||||||
@@ -343,12 +345,21 @@ class LivePlayActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun beginPlayback() {
|
private fun beginPlayback() {
|
||||||
|
startPlaybackForegroundService()
|
||||||
startPlayAttempt()
|
startPlayAttempt()
|
||||||
resetPreviewForPlayback()
|
resetPreviewForPlayback()
|
||||||
playerClient.prepareToPlay()
|
playerClient.prepareToPlay()
|
||||||
playerClient.play()
|
playerClient.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startPlaybackForegroundService() {
|
||||||
|
LivePlayForegroundService.start(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopPlaybackForegroundService() {
|
||||||
|
LivePlayForegroundService.stop(this)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setPlayingUi(playing: Boolean) {
|
private fun setPlayingUi(playing: Boolean) {
|
||||||
isPlaying = playing
|
isPlaying = playing
|
||||||
binding.tvPlayLabel.setText(if (playing) R.string.play_ctrl_pause else R.string.play_ctrl_play)
|
binding.tvPlayLabel.setText(if (playing) R.string.play_ctrl_pause else R.string.play_ctrl_play)
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.demo.SellyCloudSDK.live
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.ServiceCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.demo.SellyCloudSDK.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前台播放服务:用于在后台持续拉流并避免系统回收。
|
||||||
|
* 仅负责展示常驻通知,不绑定播放业务。
|
||||||
|
*/
|
||||||
|
class LivePlayForegroundService : Service() {
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
ServiceCompat.startForeground(
|
||||||
|
this,
|
||||||
|
NOTIFICATION_ID,
|
||||||
|
buildNotification(),
|
||||||
|
android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
startForeground(NOTIFICATION_ID, buildNotification())
|
||||||
|
}
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?) = null
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
try {
|
||||||
|
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
}
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildNotification(): Notification {
|
||||||
|
ensureChannel()
|
||||||
|
return NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
|
.setContentTitle(getString(R.string.live_play_foreground_title))
|
||||||
|
.setContentText(getString(R.string.live_play_foreground_text))
|
||||||
|
.setSmallIcon(android.R.drawable.ic_media_play)
|
||||||
|
.setOngoing(true)
|
||||||
|
.setOnlyAlertOnce(true)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val manager = getSystemService(NotificationManager::class.java) ?: return
|
||||||
|
val existing = manager.getNotificationChannel(CHANNEL_ID)
|
||||||
|
if (existing == null) {
|
||||||
|
val channel = NotificationChannel(
|
||||||
|
CHANNEL_ID,
|
||||||
|
"Live Playback",
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
)
|
||||||
|
manager.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CHANNEL_ID = "live_play_foreground"
|
||||||
|
private const val NOTIFICATION_ID = 0x201
|
||||||
|
|
||||||
|
fun start(context: Context) {
|
||||||
|
val intent = Intent(context, LivePlayForegroundService::class.java)
|
||||||
|
ContextCompat.startForegroundService(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop(context: Context) {
|
||||||
|
val intent = Intent(context, LivePlayForegroundService::class.java)
|
||||||
|
context.stopService(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -97,6 +97,8 @@
|
|||||||
<string name="play_ctrl_unmute">取消静音</string>
|
<string name="play_ctrl_unmute">取消静音</string>
|
||||||
<string name="play_ctrl_screenshot">截图</string>
|
<string name="play_ctrl_screenshot">截图</string>
|
||||||
<string name="play_ctrl_pip">画中画</string>
|
<string name="play_ctrl_pip">画中画</string>
|
||||||
|
<string name="live_play_foreground_title">正在播放</string>
|
||||||
|
<string name="live_play_foreground_text">直播播放保持中</string>
|
||||||
|
|
||||||
<string name="live_stats_title">直播数据</string>
|
<string name="live_stats_title">直播数据</string>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user