refactor(servicing): 重构推送消息处理机制
- 新增 ZdPushServiceReceive 类用于集中处理推送消息 - 优化了消息处理逻辑,提高了代码的可维护性和可扩展性 -改进了消息在主进程中的广播发送方式 - 优化了语音播放逻辑,提高了播放的稳定性和流畅性 - 调整了通知渠道的创建和通知的发送方式
This commit is contained in:
8
.idea/deploymentTargetSelector.xml
generated
8
.idea/deploymentTargetSelector.xml
generated
@ -4,6 +4,14 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2025-04-27T03:49:03.966203100Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=4f3d584c" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
|
@ -27,7 +27,7 @@ class MainActivity : ComponentActivity() {
|
||||
.fillMaxSize()
|
||||
.clickable {
|
||||
val uri =
|
||||
"zd.assist://app?taskCode=ZD250427100009&driverName=宋志领&driverPhone=17630035658&rescueVehicle=沪88888".toUri()
|
||||
"zd.assist://app?taskCode=ZD250429100095&driverName=宋志领&driverPhone=17630035658&rescueVehicle=沪88888".toUri()
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ publishing {
|
||||
release(MavenPublication) {
|
||||
groupId = 'io.github.szl9'
|
||||
artifactId = 'zd_servicing'
|
||||
version = "1.0.1.9.9.25"
|
||||
version = "1.0.1.9.9.31"
|
||||
|
||||
pom {
|
||||
packaging = "aar"
|
||||
|
@ -256,6 +256,14 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="com.za.service.ZdPushServiceReceive"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.zd.servicing.PUSH_MESSAGE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name="cn.jpush.android.service.DaemonService"
|
||||
android:enabled="true"
|
||||
|
@ -1,130 +1,58 @@
|
||||
package com.za.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.blankj.utilcode.util.ActivityUtils
|
||||
import com.google.gson.Gson
|
||||
import com.za.base.BaseActivityLifecycleCallbacks.Companion.getCurrentActivity
|
||||
import com.za.bean.JpushBean
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.common.speech.SpeechManager
|
||||
import com.za.servicing.R
|
||||
import com.za.ui.servicing.order_give_up.OrderGiveUpActivity
|
||||
import com.za.ui.view.CommonDialogFragment
|
||||
import com.za.service.PushListener
|
||||
import com.za.service.ServiceManager
|
||||
import com.za.service.ZdPushServiceReceive
|
||||
|
||||
open class PushMessageActivity : AppCompatActivity() {
|
||||
private var pushMessageReceiver : BroadcastReceiver? = null
|
||||
private var currentDialog : AlertDialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState : Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (! GlobalData.isMaster && pushMessageReceiver == null) {
|
||||
registerPushMessageReceiver(this)
|
||||
}
|
||||
setupPushMessageReceiver()
|
||||
}
|
||||
|
||||
private fun registerPushMessageReceiver(context : Context) {
|
||||
pushMessageReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context : Context?, intent : Intent?) {
|
||||
if (intent?.action == "com.za.rescue.dealer.PUSH_MESSAGE") {
|
||||
val type = intent.getStringExtra("type") ?: return
|
||||
val message = intent.getStringExtra("message") ?: return
|
||||
LogUtil.print("PushActivityLifecycleCallbacks", "收到来自远程进程的消息: $type")
|
||||
when (type) {
|
||||
"broadcast" -> handleBroadcast("broadcast:$message")
|
||||
"giveUp" -> {
|
||||
try {
|
||||
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
|
||||
val activity =
|
||||
getCurrentActivity() ?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleGiveUpOrder(activity, jpushBean)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理订单放弃消息失败: ${e.message}")
|
||||
}
|
||||
private fun setupPushMessageReceiver() { // 注册推送消息接收器
|
||||
ServiceManager.registerPushListener(object : PushListener {
|
||||
override fun broadcast(msg : String) {
|
||||
sendMessageToMainProcess("broadcast", msg)
|
||||
}
|
||||
|
||||
"importantTip" -> {
|
||||
try {
|
||||
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
|
||||
val activity =
|
||||
getCurrentActivity() ?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleImportantTip(activity, jpushBean)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理重要提示消息失败: ${e.message}")
|
||||
}
|
||||
override fun giveUpOrder(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("giveUp", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
"reDispatch" -> {
|
||||
try {
|
||||
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
|
||||
val activity =
|
||||
getCurrentActivity() ?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleReDispatchOrder(activity, jpushBean)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理订单重新派发消息失败: ${e.message}")
|
||||
}
|
||||
override fun importantTip(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("importantTip", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
"revoke" -> {
|
||||
try {
|
||||
handleRevokeOrder()
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理订单撤回消息失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun newOrderMsg(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("newOrder", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
ContextCompat.registerReceiver(context,
|
||||
pushMessageReceiver,
|
||||
IntentFilter("com.za.rescue.dealer.PUSH_MESSAGE"),
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||
LogUtil.print("PushActivityLifecycleCallbacks", "注册推送消息接收器")
|
||||
override fun reDispatchOrder(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("reDispatch", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (isLastActivity()) {
|
||||
try {
|
||||
this.unregisterReceiver(pushMessageReceiver)
|
||||
pushMessageReceiver = null
|
||||
LogUtil.print("PushActivityLifecycleCallbacks", "注销推送消息接收器")
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"注销推送消息接收器失败: ${e.message}")
|
||||
}
|
||||
override fun revokeOrder(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("revoke", Gson().toJson(jpushBean))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun isLastActivity() : Boolean { // 检查是否是最后一个活动的Activity
|
||||
return ActivityUtils.getActivityList().size <= 1
|
||||
private fun sendMessageToMainProcess(type : String, message : String) { // 使用广播将消息发送到主进程
|
||||
val intent = Intent(ZdPushServiceReceive.RECEIVE_ACTION).setPackage(packageName)
|
||||
intent.putExtra("type", type)
|
||||
intent.putExtra("message", message)
|
||||
sendBroadcast(intent)
|
||||
LogUtil.print("KeepAliveService", "发送消息到主进程: $type")
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@ -132,18 +60,6 @@ open class PushMessageActivity : AppCompatActivity() {
|
||||
dismissCurrentDialog()
|
||||
}
|
||||
|
||||
// Handle broadcast messages
|
||||
private fun handleBroadcast(msg : String) {
|
||||
try {
|
||||
val content = msg.substring(10)
|
||||
sendNotification(GlobalData.application, content)
|
||||
LogUtil.print("JpushMessage", "Broadcast content: $content")
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("JpushMessage", "Broadcast failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun dismissCurrentDialog() {
|
||||
try {
|
||||
currentDialog?.dismiss()
|
||||
@ -153,116 +69,6 @@ open class PushMessageActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGiveUpOrder(activity : AppCompatActivity,
|
||||
jpushBean : JpushBean) { // 播放提示音
|
||||
playNotificationSound(this)
|
||||
|
||||
if (GlobalData.currentOrder != null && GlobalData.currentOrder?.taskId == jpushBean.taskId) {
|
||||
SpeechManager.playCurrentOrderCanceled()
|
||||
CommonDialogFragment(title = "订单放弃",
|
||||
message = buildGiveUpMessage(jpushBean),
|
||||
confirmText = "去拍照",
|
||||
cancelText = "我已了解",
|
||||
confirm = {
|
||||
OrderGiveUpActivity.goOrderGiveUpActivity(this,
|
||||
giveUpType = GIVE_UP_TYPE_NORMAL,
|
||||
taskId = jpushBean.taskId)
|
||||
}).show(this.supportFragmentManager, DIALOG_TAG_GIVE_UP)
|
||||
} else {
|
||||
SpeechManager.playOrderCanceled()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRevokeOrder() {
|
||||
playNotificationSound(this)
|
||||
SpeechManager.speech("订单被撤回") // 获取当前Activity进行处理
|
||||
this.finish()
|
||||
}
|
||||
|
||||
private fun handleReDispatchOrder(activity : AppCompatActivity, jpushBean : JpushBean) {
|
||||
playNotificationSound(this)
|
||||
currentDialog = AlertDialog.Builder(this).setTitle("订单重新派发")
|
||||
.setMessage(buildReDispatchMessage(jpushBean)).setCancelable(false)
|
||||
.setPositiveButton("确定") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
|
||||
private fun handleImportantTip(activity : AppCompatActivity, jpushBean : JpushBean) {
|
||||
playNotificationSound(this)
|
||||
SpeechManager.speech("重要提醒:${jpushBean.tipContent ?: ""}")
|
||||
currentDialog =
|
||||
AlertDialog.Builder(this).setTitle("重要提醒").setMessage(jpushBean.tipContent)
|
||||
.setNegativeButton("我已了解") { dialog : DialogInterface, _ : Int -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun buildGiveUpMessage(jpushBean : JpushBean) : String {
|
||||
return buildString {
|
||||
append("该工单已放弃")
|
||||
jpushBean.taskCode?.let { append("\n\n订单号:$it") }
|
||||
jpushBean.address?.let { append("\n地址:$it") }
|
||||
append("\n\n是否需要拍放空照片?")
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildReDispatchMessage(jpushBean : JpushBean) : String {
|
||||
return buildString {
|
||||
append("该订单已重新派发")
|
||||
jpushBean.taskCode?.let { append("\n\n订单号:$it") }
|
||||
jpushBean.address?.let { append("\n地址:$it") }
|
||||
jpushBean.addressRemark?.let {
|
||||
if (it.isNotBlank()) {
|
||||
append("\n\n备注:$it")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun playNotificationSound(activity : Activity) {
|
||||
try {
|
||||
val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
RingtoneManager.getRingtone(activity, notification)?.play()
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks", "播放提示音失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private val CHANNEL_ID = "ImportantMessagesChannel"
|
||||
private val NOTIFICATION_ID = 1003
|
||||
|
||||
// Initialize notification channel
|
||||
private fun createNotificationChannel(context : Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(CHANNEL_ID,
|
||||
"订单通知",
|
||||
NotificationManager.IMPORTANCE_HIGH).apply {
|
||||
description = "用于接收重要消息通知"
|
||||
setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
||||
Notification.AUDIO_ATTRIBUTES_DEFAULT)
|
||||
enableVibration(true)
|
||||
}
|
||||
val notificationManager =
|
||||
context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
// Send notification
|
||||
private fun sendNotification(context : Context, message : String) {
|
||||
createNotificationChannel(context)
|
||||
val notification =
|
||||
NotificationCompat.Builder(context, CHANNEL_ID).setContentTitle("重要通知")
|
||||
.setContentText(message).setSmallIcon(R.mipmap.ic_launcher) // 替换为你的应用图标
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH).setAutoCancel(true) // 点击后自动取消通知
|
||||
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
|
||||
.setVibrate(longArrayOf(0, 100, 200, 300)).build()
|
||||
|
||||
val notificationManager =
|
||||
context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val GIVE_UP_TYPE_NORMAL = 1
|
||||
internal const val DIALOG_TAG_GIVE_UP = "giveUp"
|
||||
|
@ -95,10 +95,11 @@ object GlobalData : GlobalLocalData() {
|
||||
|
||||
var currentLocation : AMapLocation? = null
|
||||
get() {
|
||||
return field
|
||||
return mmkv.decodeParcelable("currentLocation", AMapLocation::class.java)
|
||||
}
|
||||
set(value) {
|
||||
value?.time = System.currentTimeMillis()
|
||||
value?.time= System.currentTimeMillis()
|
||||
mmkv.encode("currentLocation", value)
|
||||
field = value
|
||||
}
|
||||
|
||||
@ -117,7 +118,7 @@ object GlobalData : GlobalLocalData() {
|
||||
currentLocation = null
|
||||
driverInfoBean = null
|
||||
loginTime = null
|
||||
// isLoginRecognition = null
|
||||
isLoginRecognition = null
|
||||
}
|
||||
|
||||
fun clearAllOrderCache() {
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.za.common.speech
|
||||
|
||||
import android.app.Application
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaPlayer
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.blankj.utilcode.util.ThreadUtils
|
||||
import com.za.base.AppConfig
|
||||
import com.za.bean.request.AppNewOrderVoiceRequest
|
||||
import com.za.common.GlobalData
|
||||
@ -16,7 +16,11 @@ import com.za.room.db.user.LocalResourceBean
|
||||
import com.za.servicing.R
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kotlin.concurrent.thread
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
object SpeechManager {
|
||||
private var mContext : Application? = null
|
||||
@ -65,6 +69,7 @@ object SpeechManager {
|
||||
}
|
||||
val audioManager =
|
||||
ContextCompat.getSystemService(GlobalData.application, AudioManager::class.java)
|
||||
originVolume = audioManager?.getStreamVolume(AudioManager.STREAM_MUSIC) ?: 0
|
||||
val maxVolume = audioManager?.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
||||
audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC,
|
||||
maxVolume ?: 1,
|
||||
@ -127,60 +132,89 @@ object SpeechManager {
|
||||
}
|
||||
|
||||
private fun playNewOrder() {
|
||||
stopPlayMedia()
|
||||
try { // 先释放之前的MediaPlayer实例,避免资源泄漏
|
||||
releaseMediaPlayer()
|
||||
|
||||
// 创建新的MediaPlayer实例
|
||||
mediaPlayer = MediaPlayer.create(GlobalData.application, R.raw.neworder)
|
||||
mediaPlayer?.setOnCompletionListener { // 播放完成后释放资源
|
||||
releaseMediaPlayer()
|
||||
}
|
||||
mediaPlayer?.setOnErrorListener { mp, what, extra ->
|
||||
LogUtil.print("playNewOrder", "MediaPlayer错误: what=$what, extra=$extra")
|
||||
releaseMediaPlayer()
|
||||
true
|
||||
}
|
||||
|
||||
// 设置最大音量
|
||||
setMaxAudioVolume()
|
||||
mediaPlayer = MediaPlayer.create(mContext, R.raw.neworder)
|
||||
|
||||
// 开始播放
|
||||
mediaPlayer?.start()
|
||||
mediaPlayer?.setOnCompletionListener {
|
||||
resetAudioVolume()
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("playNewOrder", "播放出错: ${e.message}")
|
||||
releaseMediaPlayer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun playNewOrderFromNet(url : String) {
|
||||
try {
|
||||
stopPlayMedia()
|
||||
setMaxAudioVolume()
|
||||
try { // 先释放之前的MediaPlayer实例
|
||||
LogUtil.print("playNewOrderFromNet", "播放新订单语音: $url")
|
||||
releaseMediaPlayer() // 创建新的MediaPlayer实例
|
||||
mediaPlayer = MediaPlayer()
|
||||
mediaPlayer?.setAudioStreamType(AudioManager.STREAM_MUSIC) // 设置音频流类型
|
||||
mediaPlayer?.setDataSource(url) // 设置音频文件的 URL
|
||||
mediaPlayer?.prepareAsync() // 异步准备音频
|
||||
// 准备完成后开始播放
|
||||
mediaPlayer?.setOnPreparedListener { obj : MediaPlayer -> obj.start() }
|
||||
mediaPlayer?.setOnErrorListener { mp : MediaPlayer?, what : Int, extra : Int ->
|
||||
playNewOrder()
|
||||
false
|
||||
mediaPlayer?.setAudioAttributes(AudioAttributes.Builder()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA).build())
|
||||
|
||||
mediaPlayer?.setDataSource(url)
|
||||
mediaPlayer?.setOnPreparedListener { // 设置最大音量
|
||||
setMaxAudioVolume() // 准备完成后开始播放
|
||||
it.start()
|
||||
}
|
||||
mediaPlayer?.setOnCompletionListener {
|
||||
resetAudioVolume()
|
||||
mediaPlayer?.setOnCompletionListener { // 播放完成后释放资源
|
||||
releaseMediaPlayer()
|
||||
}
|
||||
mediaPlayer?.setOnErrorListener { mp, what, extra ->
|
||||
LogUtil.print("playNewOrderFromNet", "MediaPlayer错误: what=$what, extra=$extra")
|
||||
releaseMediaPlayer()
|
||||
true
|
||||
}
|
||||
|
||||
// 异步准备,避免阻塞UI线程
|
||||
mediaPlayer?.prepareAsync()
|
||||
} catch (e : Exception) {
|
||||
playNewOrder()
|
||||
LogUtil.print("播放新订单失败", e)
|
||||
LogUtil.print("playNewOrderFromNet", "播放出错: ${e.message}")
|
||||
releaseMediaPlayer()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopPlayMedia() {
|
||||
ThreadUtils.runOnUiThread {
|
||||
if (null != mediaPlayer) {
|
||||
mediaPlayer?.stop()
|
||||
mediaPlayer?.release()
|
||||
mediaPlayer = null
|
||||
// 安全释放MediaPlayer资源
|
||||
fun releaseMediaPlayer() {
|
||||
try {
|
||||
mediaPlayer?.let {
|
||||
if (it.isPlaying) {
|
||||
it.stop()
|
||||
}
|
||||
it.reset()
|
||||
it.release()
|
||||
}
|
||||
mediaPlayer = null // 恢复原始音量
|
||||
resetAudioVolume()
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("releaseMediaPlayer", "释放MediaPlayer出错: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun speechNewOrderSound(content : String?) {
|
||||
if (content.isNullOrBlank()) {
|
||||
speechNewOrderLooper("您有新的中道救援订单,请尽快接单!") { playNewOrder() }
|
||||
speechNewOrderLocalSoundLooper()
|
||||
return
|
||||
}
|
||||
|
||||
val localResourceDao = RoomHelper.db?.localResourceDao()
|
||||
val localUrlResource = localResourceDao?.getLocalResourceByName(content)
|
||||
if (localUrlResource != null && ! localUrlResource.resourceUrl.isNullOrBlank()) {
|
||||
speechNewOrderLooper(content) {
|
||||
playNewOrderFromNet(localUrlResource.resourceUrl)
|
||||
}
|
||||
speechNewOrderNetLooper(content, localUrlResource.resourceUrl ?: "")
|
||||
LogUtil.print("handlerNewOrderVoice", "播放本地语音");
|
||||
return
|
||||
}
|
||||
@ -191,28 +225,59 @@ object SpeechManager {
|
||||
.subscribe(object : BaseObserver<String>() {
|
||||
override fun doSuccess(it : String?) {
|
||||
if (it == null) {
|
||||
speechNewOrderLooper(content) { playNewOrder() }
|
||||
speechNewOrderLocalSoundLooper()
|
||||
return
|
||||
}
|
||||
localResourceDao?.insert(LocalResourceBean(resourceName = content,
|
||||
resourceType = 1,
|
||||
resourceUrl = it))
|
||||
speechNewOrderLooper(content) { playNewOrderFromNet(it) }
|
||||
speechNewOrderNetLooper(content, it)
|
||||
}
|
||||
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
speechNewOrderLooper("您有新的中道救援订单,请尽快接单!") { playNewOrder() }
|
||||
speechNewOrderLocalSoundLooper()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun speechNewOrderLooper(content : String, play : () -> Unit) {
|
||||
thread {
|
||||
|
||||
private fun speechNewOrderLocalSoundLooper() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val startTime = System.currentTimeMillis()
|
||||
while (System.currentTimeMillis() - startTime < 1000 * 60 * 3 && GlobalData.isHandlerNewOrder == false) {
|
||||
play()
|
||||
Thread.sleep(250L * content.length)
|
||||
try {
|
||||
delay(250L * "您有新的中道救援订单,请尽快接单!".length)
|
||||
withContext(Dispatchers.Main) {
|
||||
playNewOrder()
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("speechNewOrderLooper",
|
||||
"播放循环出错: ${e.message}") // 出错时也要等待一下,避免无限循环
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
GlobalData.isHandlerNewOrder = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun speechNewOrderNetLooper(content : String, url : String) {
|
||||
val url = url.replace("http://", "https://")
|
||||
GlobalData.isHandlerNewOrder = false
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val startTime = System.currentTimeMillis()
|
||||
while (System.currentTimeMillis() - startTime < 1000 * 60 * 3 && GlobalData.isHandlerNewOrder == false) {
|
||||
try {
|
||||
withContext(Dispatchers.Main) {
|
||||
playNewOrderFromNet(url)
|
||||
}
|
||||
delay(250L * content.length)
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("speechNewOrderLooper",
|
||||
"播放循环出错: ${e.message}") // 出错时也要等待一下,避免无限循环
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
GlobalData.isHandlerNewOrder = false
|
||||
}
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ interface PushListener {
|
||||
fun importantTip(jpushBean : JpushBean)
|
||||
}
|
||||
|
||||
data class LastJPushBean(val msg : Int, val time : Long = System.nanoTime())
|
||||
data class LastJPushBean(val msg : String, val time : Long = System.currentTimeMillis())
|
||||
|
||||
object ServiceManager {
|
||||
@Volatile
|
||||
@ -115,21 +115,21 @@ object ServiceManager {
|
||||
|
||||
// 优化后的重复消息判断
|
||||
lastJPushBean?.let {
|
||||
if (System.nanoTime() - it.time < DUPLICATE_MSG_THRESHOLD && it.msg == msg.hashCode()) {
|
||||
if (System.currentTimeMillis() - it.time < DUPLICATE_MSG_THRESHOLD && it.msg == msg) {
|
||||
LogUtil.print("MessageHandler", "Duplicate message detected (hash: ${msg})")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.startsWith("broadcast:")) {
|
||||
lastJPushBean = LastJPushBean(msg = msg.hashCode())
|
||||
handleBroadcast(msg) // PushMessageLiveData.postPushMessage(msg)
|
||||
lastJPushBean = LastJPushBean(msg = msg)
|
||||
handleBroadcast(msg)
|
||||
return
|
||||
}
|
||||
try {
|
||||
lastJPushBean = LastJPushBean(msg = msg.hashCode())
|
||||
lastJPushBean = LastJPushBean(msg = msg)
|
||||
val jpushOrderInfoBean = Gson().fromJson(msg, JpushBean::class.java)
|
||||
sendSystemNotificationFromMessage(jpushOrderInfoBean) // PushMessageLiveData.postPushMessage(msg)
|
||||
sendSystemNotificationFromMessage(jpushOrderInfoBean)
|
||||
when (jpushOrderInfoBean.pushType) {
|
||||
0 -> newOrderMsg(jpushOrderInfoBean)
|
||||
1 -> handleTypeOneMessage(jpushOrderInfoBean)
|
||||
@ -138,7 +138,7 @@ object ServiceManager {
|
||||
"Unknown push type: ${jpushOrderInfoBean.pushType}")
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
if (msg.startsWith("broadcast:")) { // PushMessageLiveData.postPushMessage(msg)
|
||||
if (msg.startsWith("broadcast:")) {
|
||||
handleBroadcast(msg)
|
||||
}
|
||||
LogUtil.print("JpushMessage", "Error handling message: ${e.message}")
|
||||
|
237
servicing/src/main/java/com/za/service/ZdPushServiceReceive.kt
Normal file
237
servicing/src/main/java/com/za/service/ZdPushServiceReceive.kt
Normal file
@ -0,0 +1,237 @@
|
||||
package com.za.service
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.blankj.utilcode.util.ActivityUtils
|
||||
import com.blankj.utilcode.util.AppUtils
|
||||
import com.google.gson.Gson
|
||||
import com.za.base.BaseActivityLifecycleCallbacks
|
||||
import com.za.bean.JpushBean
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.common.speech.SpeechManager
|
||||
import com.za.servicing.R
|
||||
import com.za.ui.servicing.order_give_up.OrderGiveUpActivity
|
||||
import com.za.ui.view.CommonDialogFragment
|
||||
|
||||
class ZdPushServiceReceive : BroadcastReceiver() {
|
||||
companion object {
|
||||
const val RECEIVE_ACTION = "com.zd.servicing.PUSH_MESSAGE"
|
||||
private const val GIVE_UP_TYPE_NORMAL = 1
|
||||
private const val DIALOG_TAG_GIVE_UP = "giveUp"
|
||||
}
|
||||
|
||||
private fun handlerMessage(context : Context?, intent : Intent?) {
|
||||
val activity = context ?: ActivityUtils.getTopActivity()
|
||||
activity as? AppCompatActivity
|
||||
if (intent?.action == RECEIVE_ACTION) {
|
||||
val type = intent.getStringExtra("type") ?: return
|
||||
val message = intent.getStringExtra("message") ?: return
|
||||
if (ActivityUtils.getTopActivity() == null) {
|
||||
AppUtils.launchApp(GlobalData.application.packageName)
|
||||
}
|
||||
LogUtil.print("PushActivityLifecycleCallbacks", "收到来自远程进程的消息: $type")
|
||||
when (type) {
|
||||
"broadcast" -> handleBroadcast("broadcast:$message")
|
||||
|
||||
"giveUp" -> {
|
||||
try {
|
||||
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
|
||||
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
|
||||
?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleGiveUpOrder(activity, jpushBean)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理订单放弃消息失败: ${e.message}")
|
||||
}
|
||||
} // 处理其他类型的消息...
|
||||
"importantTip" -> {
|
||||
try {
|
||||
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
|
||||
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
|
||||
?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleImportantTip(activity, jpushBean)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理重要提示消息失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
"reDispatch" -> {
|
||||
try {
|
||||
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
|
||||
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
|
||||
?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleReDispatchOrder(activity, jpushBean)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理订单重新派发消息失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
"revoke" -> {
|
||||
try {
|
||||
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
|
||||
?: ActivityUtils.getTopActivity()
|
||||
if (activity is AppCompatActivity) {
|
||||
handleRevokeOrder(activity)
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks",
|
||||
"处理订单撤回消息失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGiveUpOrder(activity : Activity, jpushBean : JpushBean) {
|
||||
if (activity !is AppCompatActivity) return
|
||||
|
||||
// 播放提示音
|
||||
playNotificationSound(activity)
|
||||
|
||||
if (GlobalData.currentOrder != null && GlobalData.currentOrder?.taskId == jpushBean.taskId) {
|
||||
SpeechManager.playCurrentOrderCanceled()
|
||||
CommonDialogFragment(title = "订单放弃",
|
||||
message = buildGiveUpMessage(jpushBean),
|
||||
confirmText = "去拍照",
|
||||
cancelText = "我已了解",
|
||||
confirm = {
|
||||
OrderGiveUpActivity.Companion.goOrderGiveUpActivity(activity,
|
||||
giveUpType = GIVE_UP_TYPE_NORMAL,
|
||||
taskId = jpushBean.taskId)
|
||||
}).show(activity.supportFragmentManager, DIALOG_TAG_GIVE_UP)
|
||||
} else {
|
||||
SpeechManager.playOrderCanceled()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRevokeOrder(activity : Activity) {
|
||||
playNotificationSound(activity)
|
||||
SpeechManager.speech("订单被撤回")
|
||||
ActivityUtils.getTopActivity().finish()
|
||||
}
|
||||
|
||||
private fun handleReDispatchOrder(activity : Activity, jpushBean : JpushBean) {
|
||||
playNotificationSound(activity)
|
||||
BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()?.let { currentActivity ->
|
||||
if (currentActivity is AppCompatActivity) {
|
||||
AlertDialog.Builder(currentActivity).setTitle("订单重新派发")
|
||||
.setMessage(buildReDispatchMessage(jpushBean)).setCancelable(false)
|
||||
.setPositiveButton("确定") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
currentActivity.finish()
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleImportantTip(activity : Activity, jpushBean : JpushBean) {
|
||||
playNotificationSound(activity)
|
||||
SpeechManager.speech("重要提醒:${jpushBean.tipContent ?: ""}")
|
||||
AlertDialog.Builder(activity).setTitle("重要提醒").setMessage(jpushBean.tipContent)
|
||||
.setNegativeButton("我已了解") { dialog : DialogInterface, _ : Int -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
||||
// Handle broadcast messages
|
||||
private fun handleBroadcast(msg : String) {
|
||||
try {
|
||||
val content = msg.substring(10)
|
||||
sendNotification(GlobalData.application, content)
|
||||
LogUtil.print("JpushMessage", "Broadcast content: $content")
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("JpushMessage", "Broadcast failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildReDispatchMessage(jpushBean : JpushBean) : String {
|
||||
return buildString {
|
||||
append("该订单已重新派发")
|
||||
jpushBean.taskCode?.let { append("\n\n订单号:$it") }
|
||||
jpushBean.address?.let { append("\n地址:$it") }
|
||||
jpushBean.addressRemark?.let {
|
||||
if (it.isNotBlank()) {
|
||||
append("\n\n备注:$it")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun buildGiveUpMessage(jpushBean : JpushBean) : String {
|
||||
return buildString {
|
||||
append("该工单已放弃")
|
||||
jpushBean.taskCode?.let { append("\n\n订单号:$it") }
|
||||
jpushBean.address?.let { append("\n地址:$it") }
|
||||
append("\n\n是否需要拍放空照片?")
|
||||
}
|
||||
}
|
||||
|
||||
private fun playNotificationSound(activity : Activity?) {
|
||||
try {
|
||||
val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
RingtoneManager.getRingtone(activity, notification)?.play()
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("PushActivityLifecycleCallbacks", "播放提示音失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private val CHANNEL_ID = "ImportantMessagesChannel"
|
||||
private val NOTIFICATION_ID = 1003
|
||||
|
||||
// Initialize notification channel
|
||||
private fun createNotificationChannel(context : Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(CHANNEL_ID,
|
||||
"订单通知",
|
||||
NotificationManager.IMPORTANCE_HIGH).apply {
|
||||
description = "用于接收重要消息通知"
|
||||
setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
||||
Notification.AUDIO_ATTRIBUTES_DEFAULT)
|
||||
enableVibration(true)
|
||||
}
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
// Send notification
|
||||
private fun sendNotification(context : Context, message : String) {
|
||||
createNotificationChannel(context)
|
||||
val notification =
|
||||
NotificationCompat.Builder(context, CHANNEL_ID).setContentTitle("重要通知")
|
||||
.setContentText(message).setSmallIcon(R.mipmap.ic_launcher) // 替换为你的应用图标
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH).setAutoCancel(true) // 点击后自动取消通知
|
||||
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
|
||||
.setVibrate(longArrayOf(0, 100, 200, 300)).build()
|
||||
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
override fun onReceive(context : Context?, intent : Intent?) {
|
||||
handlerMessage(context, intent)
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ class ConnectionOptionWrapper(
|
||||
*/
|
||||
@JvmField
|
||||
val mqttConnectOptions: MqttConnectOptions = MqttConnectOptions().apply {
|
||||
isCleanSession = false
|
||||
isCleanSession = true
|
||||
keepAliveInterval = 90 // Keep alive interval in seconds
|
||||
isAutomaticReconnect = true
|
||||
mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1
|
||||
|
@ -46,20 +46,25 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.blankj.utilcode.util.ActivityUtils
|
||||
import com.google.gson.Gson
|
||||
import com.za.base.BaseActivity
|
||||
import com.za.base.theme.bgColor
|
||||
import com.za.base.view.CommonButton
|
||||
import com.za.base.view.EmptyView
|
||||
import com.za.base.view.HeadView
|
||||
import com.za.base.view.LoadError
|
||||
import com.za.bean.JpushBean
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.common.util.DeviceUtil
|
||||
import com.za.ext.convertToFlowName
|
||||
import com.za.ext.copy
|
||||
import com.za.ext.finish
|
||||
import com.za.ext.goStatusPage
|
||||
import com.za.service.PushListener
|
||||
import com.za.service.ServiceManager
|
||||
import com.za.service.ZdPushServiceReceive
|
||||
import com.za.service.location.ZdLocationManager
|
||||
import com.za.servicing.R
|
||||
import kotlinx.coroutines.launch
|
||||
@ -77,6 +82,47 @@ class ServicingMainActivity : BaseActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupPushMessageReceiver()
|
||||
}
|
||||
|
||||
private fun setupPushMessageReceiver() { // 注册推送消息接收器
|
||||
ServiceManager.registerPushListener(object : PushListener {
|
||||
override fun broadcast(msg : String) {
|
||||
sendMessageToMainProcess("broadcast", msg)
|
||||
}
|
||||
|
||||
override fun giveUpOrder(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("giveUp", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
override fun importantTip(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("importantTip", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
override fun newOrderMsg(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("newOrder", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
override fun reDispatchOrder(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("reDispatch", Gson().toJson(jpushBean))
|
||||
}
|
||||
|
||||
override fun revokeOrder(jpushBean : JpushBean) {
|
||||
sendMessageToMainProcess("revoke", Gson().toJson(jpushBean))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendMessageToMainProcess(type : String, message : String) { // 使用广播将消息发送到主进程
|
||||
val intent = Intent(ZdPushServiceReceive.RECEIVE_ACTION).setPackage(packageName)
|
||||
intent.putExtra("type", type)
|
||||
intent.putExtra("message", message)
|
||||
sendBroadcast(intent)
|
||||
LogUtil.print(TAG, "发送消息到主进程: $type")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun goToMain(context : Context,
|
||||
driverName : String? = null,
|
||||
@ -116,6 +162,7 @@ private fun ServicingMainScreen(jobCode : String? = null,
|
||||
scope.launch {
|
||||
ServiceManager.initialize(GlobalData.application)
|
||||
ZdLocationManager.startContinuousLocation(GlobalData.application)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ class ModifyMoneyViewModel : BaseVm<Action, UiState>() {
|
||||
userOrderId = userOrderId,
|
||||
taskId = taskId,
|
||||
unitPrice = it?.unitPrice,
|
||||
mileage = it?.amount,
|
||||
mileage = it?.mileage,
|
||||
mileageText = "${it?.mileage ?: ""}",
|
||||
calculateAmount = it?.calculateAmount,
|
||||
adjustAmount = it?.adjustAmount?.toFloat(),
|
||||
|
Reference in New Issue
Block a user