TokenUtil.kt迁移到lib模块 根build.gradle.kts迁移变量到子模块 增加拉取通知的后台服务 MessageService.kt 增加通知相关接口master
parent
94b057d1cf
commit
e7f07a3415
@ -1,30 +0,0 @@ |
|||||||
package com.gyf.csams.util |
|
||||||
|
|
||||||
import android.app.Activity |
|
||||||
import android.view.View |
|
||||||
import android.view.inputmethod.InputMethodManager |
|
||||||
import com.orhanobut.logger.Logger |
|
||||||
|
|
||||||
object ContextUtil { |
|
||||||
fun hideKeyBoard(activity: Activity?) { |
|
||||||
Logger.i("隐藏软键盘") |
|
||||||
activity?.apply { |
|
||||||
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager |
|
||||||
window.peekDecorView()?.let { |
|
||||||
imm.hideSoftInputFromWindow(it.windowToken, 0) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fun testHideKeyBoard(activity: Activity) { |
|
||||||
Logger.i("隐藏软键盘") |
|
||||||
val imm = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager |
|
||||||
//Find the currently focused view, so we can grab the correct window token from it. |
|
||||||
var view: View? = activity.currentFocus |
|
||||||
//If no view currently has focus, create a new one, just so we can grab a window token from it |
|
||||||
if (view == null) { |
|
||||||
view = View(activity) |
|
||||||
} |
|
||||||
imm.hideSoftInputFromWindow(view.windowToken, 0) |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,73 @@ |
|||||||
|
package com.gyf |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import androidx.work.Data |
||||||
|
import androidx.work.Worker |
||||||
|
import androidx.work.WorkerParameters |
||||||
|
import com.google.gson.Gson |
||||||
|
import com.google.gson.reflect.TypeToken |
||||||
|
import com.gyf.lib.BuildConfig |
||||||
|
import com.gyf.lib.util.* |
||||||
|
|
||||||
|
import com.orhanobut.logger.Logger |
||||||
|
import java.net.SocketTimeoutException |
||||||
|
|
||||||
|
const val NOTIFICATION_API = "${BuildConfig.SERVER_ADDRESS}/api/notification/pull" |
||||||
|
|
||||||
|
data class NotificationVo(val title: String, val content: String, val id: Int) |
||||||
|
|
||||||
|
data class PageDto(val currentPage: Long, val pageSize: Int = 10) |
||||||
|
|
||||||
|
data class NotificationDto( |
||||||
|
val receiverId: Int, |
||||||
|
val receiverClient: String, |
||||||
|
override val token: Token, |
||||||
|
val page: PageDto? = null |
||||||
|
) : BaseToken() |
||||||
|
|
||||||
|
/** |
||||||
|
* 通知接收客户端 |
||||||
|
* |
||||||
|
*/ |
||||||
|
enum class ReceiverType { |
||||||
|
//前台 |
||||||
|
Foreground, |
||||||
|
|
||||||
|
//后台 |
||||||
|
Background |
||||||
|
} |
||||||
|
|
||||||
|
class NotificationWorker(context: Context, workerParams: WorkerParameters) : |
||||||
|
Worker(context, workerParams) { |
||||||
|
|
||||||
|
override fun doWork(): Result { |
||||||
|
TokenManager.token?.let { |
||||||
|
return try { |
||||||
|
Logger.i("开始拉取通知") |
||||||
|
val data = HttpClient.postAsync<NotificationVo>(url = NOTIFICATION_API, |
||||||
|
jsonParam = NotificationDto( |
||||||
|
receiverId = it.id, |
||||||
|
receiverClient = inputData.getString("receiverClient") |
||||||
|
?: throw IllegalArgumentException("缺少receiverClient参数"), |
||||||
|
token = it |
||||||
|
), |
||||||
|
type = object : TypeToken<ApiResponse<NotificationVo>>() {}.type |
||||||
|
) |
||||||
|
val result = |
||||||
|
Data.Builder().putString(NotificationVo::class.java.name, Gson().toJson(data)) |
||||||
|
.build() |
||||||
|
Logger.i("拉取通知成功:\n${result}") |
||||||
|
Result.success(result) |
||||||
|
} catch (e: SocketTimeoutException) { |
||||||
|
Logger.e(e, "网络异常,拉取通知失败稍后再试") |
||||||
|
Result.retry() |
||||||
|
} catch (e: Exception) { |
||||||
|
Logger.e(e, "发生未知异常,中止任务") |
||||||
|
Result.failure() |
||||||
|
} |
||||||
|
} |
||||||
|
Logger.w("找不到token信息,中止任务") |
||||||
|
return Result.failure() |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package com.gyf.lib |
||||||
|
|
||||||
|
import android.content.Intent |
||||||
|
import androidx.core.app.JobIntentService |
||||||
|
import androidx.core.app.NotificationCompat |
||||||
|
import androidx.core.app.NotificationManagerCompat |
||||||
|
import com.google.gson.Gson |
||||||
|
import com.google.gson.reflect.TypeToken |
||||||
|
import com.gyf.NOTIFICATION_API |
||||||
|
import com.gyf.NotificationDto |
||||||
|
import com.gyf.NotificationVo |
||||||
|
import com.gyf.ReceiverType |
||||||
|
import com.gyf.lib.util.ApiResponse |
||||||
|
import com.gyf.lib.util.HttpClient |
||||||
|
import com.gyf.lib.util.NotificationUtil |
||||||
|
import com.gyf.lib.util.TokenManager |
||||||
|
import com.orhanobut.logger.Logger |
||||||
|
|
||||||
|
class MessageService : JobIntentService() { |
||||||
|
|
||||||
|
val gson = Gson() |
||||||
|
|
||||||
|
override fun onCreate() { |
||||||
|
super.onCreate() |
||||||
|
Logger.i("服务启动") |
||||||
|
} |
||||||
|
|
||||||
|
override fun onDestroy() { |
||||||
|
super.onDestroy() |
||||||
|
Logger.i("服务销毁") |
||||||
|
} |
||||||
|
|
||||||
|
override fun onHandleWork(intent: Intent) { |
||||||
|
TokenManager.token?.let { it -> |
||||||
|
HttpClient.postAsync<List<NotificationVo>>(url = NOTIFICATION_API, |
||||||
|
jsonParam = NotificationDto( |
||||||
|
receiverId = it.id, |
||||||
|
receiverClient = ReceiverType.Foreground.name, |
||||||
|
token = it |
||||||
|
), |
||||||
|
type = object : TypeToken<ApiResponse<List<NotificationVo>>>() {}.type |
||||||
|
)?.let { it -> |
||||||
|
Logger.i("拉取最新通知") |
||||||
|
it.body?.forEach { |
||||||
|
Logger.i("构造通知【${it.title}】") |
||||||
|
val builder = |
||||||
|
NotificationCompat.Builder(applicationContext, NotificationUtil.CHANNEL_ID) |
||||||
|
.setSmallIcon(R.drawable.ic_notification) |
||||||
|
.setContentTitle(it.title) |
||||||
|
.setContentText(it.content) |
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH) |
||||||
|
builder.build() |
||||||
|
with(NotificationManagerCompat.from(applicationContext)) { |
||||||
|
// notificationId is a unique int for each notification that you must define |
||||||
|
notify(it.id, builder.build()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
package com.gyf.lib.util |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import android.content.Context |
||||||
|
import android.view.View |
||||||
|
import android.view.inputmethod.InputMethodManager |
||||||
|
import androidx.lifecycle.LiveData |
||||||
|
import androidx.work.* |
||||||
|
import com.gyf.NotificationWorker |
||||||
|
import com.gyf.ReceiverType |
||||||
|
import com.orhanobut.logger.Logger |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
object ContextUtil { |
||||||
|
private var name = "pullNotification" |
||||||
|
|
||||||
|
private fun getNotification(context: Context): UUID { |
||||||
|
val data = Data.Builder() |
||||||
|
.putString("receiverClient", ReceiverType.Foreground.name) |
||||||
|
.build() |
||||||
|
val uploadWorkRequest: OneTimeWorkRequest = |
||||||
|
OneTimeWorkRequestBuilder<NotificationWorker>() |
||||||
|
.setInputData(data) |
||||||
|
.build() |
||||||
|
Logger.i("构建任务") |
||||||
|
val workManager = WorkManager.getInstance(context) |
||||||
|
workManager.enqueueUniqueWork(name, ExistingWorkPolicy.KEEP, uploadWorkRequest) |
||||||
|
return uploadWorkRequest.id |
||||||
|
} |
||||||
|
|
||||||
|
fun getNotificationLiveData(context: Context): LiveData<WorkInfo> { |
||||||
|
val id = getNotification(context = context) |
||||||
|
return WorkManager.getInstance(context).getWorkInfoByIdLiveData(id) |
||||||
|
} |
||||||
|
|
||||||
|
fun getNotification(context: Context, callback: (wordId: UUID) -> Unit) { |
||||||
|
callback(getNotification(context = context)) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
fun hideKeyBoard(activity: Activity?) { |
||||||
|
Logger.i("隐藏软键盘") |
||||||
|
activity?.apply { |
||||||
|
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager |
||||||
|
window.peekDecorView()?.let { |
||||||
|
imm.hideSoftInputFromWindow(it.windowToken, 0) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun testHideKeyBoard(activity: Activity) { |
||||||
|
Logger.i("隐藏软键盘") |
||||||
|
val imm = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager |
||||||
|
//Find the currently focused view, so we can grab the correct window token from it. |
||||||
|
var view: View? = activity.currentFocus |
||||||
|
//If no view currently has focus, create a new one, just so we can grab a window token from it |
||||||
|
if (view == null) { |
||||||
|
view = View(activity) |
||||||
|
} |
||||||
|
imm.hideSoftInputFromWindow(view.windowToken, 0) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2017 Google Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package com.gyf.lib.util |
||||||
|
|
||||||
|
import android.app.NotificationChannel |
||||||
|
import android.app.NotificationManager |
||||||
|
import android.content.Context |
||||||
|
import android.os.Build |
||||||
|
import androidx.core.app.NotificationCompat |
||||||
|
import com.gyf.lib.BuildConfig |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Simplifies common [Notification] tasks. |
||||||
|
*/ |
||||||
|
object NotificationUtil { |
||||||
|
// The id of the channel. |
||||||
|
const val CHANNEL_ID = BuildConfig.LIBRARY_PACKAGE_NAME |
||||||
|
|
||||||
|
fun createNotificationChannel( |
||||||
|
context: Context, |
||||||
|
channelImportance: Int |
||||||
|
): String? { |
||||||
|
// NotificationChannels are required for Notifications on O (API 26) and above. |
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||||
|
|
||||||
|
// The user-visible name of the channel. |
||||||
|
val channelName: CharSequence = "" |
||||||
|
// The user-visible description of the channel. |
||||||
|
val channelDescription = "" |
||||||
|
val channelEnableVibrate = false |
||||||
|
val channelLockscreenVisibility: Int = NotificationCompat.VISIBILITY_PUBLIC |
||||||
|
|
||||||
|
// Initializes NotificationChannel. |
||||||
|
val notificationChannel = |
||||||
|
NotificationChannel(CHANNEL_ID, channelName, channelImportance) |
||||||
|
notificationChannel.description = channelDescription |
||||||
|
notificationChannel.enableVibration(channelEnableVibrate) |
||||||
|
notificationChannel.lockscreenVisibility = channelLockscreenVisibility |
||||||
|
|
||||||
|
// Adds NotificationChannel to system. Attempting to create an existing notification |
||||||
|
// channel with its original values performs no operation, so it's safe to perform the |
||||||
|
// below sequence. |
||||||
|
val notificationManager: NotificationManager = |
||||||
|
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
||||||
|
notificationManager.createNotificationChannel(notificationChannel) |
||||||
|
CHANNEL_ID |
||||||
|
} else { |
||||||
|
// Returns null for pre-O (26) devices. |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="64dp" |
||||||
|
android:height="64dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
<path |
||||||
|
android:pathData="M752.77,955.39H257.92c-112.38,0 -203.39,-91.01 -203.39,-203.39V257.15C54.53,144.77 145.54,53.76 257.92,53.76h494.85C865.15,53.76 956.16,144.77 956.16,257.15v494.85c0,112.38 -91.01,203.39 -203.39,203.39z" |
||||||
|
android:fillColor="#FF4D3C" /> |
||||||
|
<path |
||||||
|
android:pathData="M616.58,765.95H370.56c-67.97,0 -123.01,-55.04 -123.01,-123.01V396.8c0,-67.97 55.04,-123.01 123.01,-123.01h166.27c9.98,0 18.18,8.06 18.18,18.18 0,9.98 -8.06,18.18 -18.18,18.18H370.56c-47.87,0 -86.66,38.78 -86.66,86.66v246.02c0,47.87 38.78,86.66 86.66,86.66h246.02c47.87,0 86.66,-38.78 86.66,-86.66V469.12c0,-9.98 8.06,-18.18 18.18,-18.18 9.98,0 18.18,8.06 18.18,18.18v173.82c0,67.97 -55.04,123.01 -123.01,123.01z" |
||||||
|
android:fillColor="#FFFFFF" /> |
||||||
|
<path |
||||||
|
android:pathData="M694.78,312.7m-113.41,0a113.41,113.41 0,1 0,226.82 0,113.41 113.41,0 1,0 -226.82,0Z" |
||||||
|
android:fillColor="#FFFFFF" /> |
||||||
|
</vector> |
Loading…
Reference in new issue