1箭阶、效果
2、簡(jiǎn)介
通知是 Android 在您的應(yīng)用 UI 之外顯示的消息戈鲁,用于向用戶(hù)提供提醒仇参、來(lái)自其他人的通信或來(lái)自您的應(yīng)用的其他及時(shí)信息。用戶(hù)可以點(diǎn)擊通知打開(kāi)您的應(yīng)用或直接從通知中執(zhí)行操作婆殿。
2.1诈乒、展示
- 通知以不同的位置和格式向用戶(hù)顯示,例如狀態(tài)欄中的圖標(biāo)婆芦、通知抽屜中更詳細(xì)的條目怕磨、應(yīng)用程序圖標(biāo)上的徽章以及自動(dòng)配對(duì)的可穿戴設(shè)備。
- 當(dāng)發(fā)出通知時(shí)消约,它首先在狀態(tài)欄中顯示為一個(gè)圖標(biāo)肠鲫。
2.2、操作
- 用戶(hù)可以在狀態(tài)欄上向下滑動(dòng)以打開(kāi)通知抽屜或粮,他們可以在其中查看更多詳細(xì)信息并根據(jù)通知執(zhí)行操作导饲。
- 用戶(hù)可以向下拖動(dòng)抽屜中的通知以顯示展開(kāi)的視圖,該視圖顯示其他內(nèi)容和操作按鈕(如果提供)。
- 通知在通知抽屜中保持可見(jiàn)渣锦,直到被應(yīng)用程序或用戶(hù)關(guān)閉硝岗。
3、功能拆解
本文將帶領(lǐng)實(shí)現(xiàn)各種常見(jiàn)的通知功能袋毙,以及各個(gè)Android版本需要做的適配
辈讶。
4、功能實(shí)現(xiàn)
4.0娄猫、關(guān)鍵類(lèi)
-
NotificationManager
通知管理器贱除,用來(lái)發(fā)起、更新媳溺、刪除通知 -
NotificationChannel
通知渠道月幌,8.0及以上配置渠道以及優(yōu)先級(jí) -
NotificationCompat.Builder
通知構(gòu)造器,用來(lái)配置通知的布局顯示以及操作相關(guān)
常用API悬蔽,查看第5節(jié)扯躺。 各版本適配,查看第6節(jié)蝎困。
4.1录语、普通通知
private fun createNotificationForNormal() {
// 適配8.0及以上 創(chuàng)建渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mNormalChannelId, mNormalChannelName, NotificationManager.IMPORTANCE_LOW).apply {
description = "描述"
setShowBadge(false) // 是否在桌面顯示角標(biāo)
}
mManager.createNotificationChannel(channel)
}
// 點(diǎn)擊意圖 // setDeleteIntent 移除意圖
val intent = Intent(this, MaterialButtonActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
// 構(gòu)建配置
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mNormalChannelId)
.setContentTitle("普通通知") // 標(biāo)題
.setContentText("普通通知內(nèi)容") // 文本
.setSmallIcon(R.mipmap.ic_launcher) // 小圖標(biāo)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_avatar)) // 大圖標(biāo)
.setPriority(NotificationCompat.PRIORITY_DEFAULT) // 7.0 設(shè)置優(yōu)先級(jí)
.setContentIntent(pendingIntent) // 跳轉(zhuǎn)配置
.setAutoCancel(true) // 是否自動(dòng)消失(點(diǎn)擊)or mManager.cancel(mNormalNotificationId)、cancelAll禾乘、setTimeoutAfter()
// 發(fā)起通知
mManager.notify(mNormalNotificationId, mBuilder.build())
}
發(fā)起一個(gè)普通通知的幾個(gè)要素:
- setContentTitle 標(biāo)題
- setContentText 內(nèi)容
- setSmallIcon 小圖標(biāo)
- setLargeIcon 大圖標(biāo)
- setPriority 優(yōu)先級(jí)or重要性(7.0和8.0的方式不同)
- setContentIntent 點(diǎn)擊意圖
- setAutoCancel 是否自動(dòng)取消
- notify 發(fā)起通知
4.2澎埠、重要通知
重要通知,優(yōu)先級(jí)設(shè)置最高始藕,會(huì)直接顯示在屏幕內(nèi)(前臺(tái))蒲稳,而不是只有通知抽屜里,所以一定要謹(jǐn)慎
設(shè)置伍派,不要引起用戶(hù)的負(fù)面情緒江耀。
private fun createNotificationForHigh() {
val intent = Intent(this, MaterialButtonActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mHighChannelId, mHighChannelName, NotificationManager.IMPORTANCE_HIGH)
channel.setShowBadge(true)
mManager.createNotificationChannel(channel)
}
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mHighChannelId)
.setContentTitle("重要通知")
.setContentText("重要通知內(nèi)容")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_avatar))
.setAutoCancel(true)
.setNumber(999) // 自定義桌面通知數(shù)量
.addAction(R.mipmap.ic_avatar, "去看看", pendingIntent)// 通知上的操作
.setCategory(NotificationCompat.CATEGORY_MESSAGE) // 通知類(lèi)別,"勿擾模式"時(shí)系統(tǒng)會(huì)決定要不要顯示你的通知
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE) // 屏幕可見(jiàn)性诉植,鎖屏?xí)r祥国,顯示icon和標(biāo)題,內(nèi)容隱藏
mManager.notify(mHighNotificationId, mBuilder.build())
}
這里有幾個(gè)新增的配置:
- setNumber 桌面通知數(shù)量
- addAction 通知上的操作
- setCategory 通知類(lèi)別晾腔,"勿擾模式"時(shí)系統(tǒng)會(huì)決定要不要顯示你的通知
- setVisibility 屏幕可見(jiàn)性舌稀,鎖屏?xí)r,顯示icon和標(biāo)題建车,內(nèi)容隱藏扩借,解鎖查看全部
4.2.1椒惨、通知上的操作
可以通過(guò)addAction
在通知上添加一個(gè)自定義操作缤至,如上圖:去看看。
可以通過(guò)PendingIntent
打開(kāi)一個(gè)Activity,也可以是發(fā)送一個(gè)廣播领斥。
在Android10.0
及以上嫉到,系統(tǒng)也會(huì)默認(rèn)識(shí)別并添加一些操作,比如短信通知上的「復(fù)制驗(yàn)證碼」月洛。
4.2.2何恶、重要性等級(jí)
- 緊急:發(fā)出聲音并顯示為提醒通知
- 高:發(fā)出聲音
- 中:沒(méi)有聲音
- 低:無(wú)聲音且不出現(xiàn)在狀態(tài)欄中
4.3、進(jìn)度條通知
private fun createNotificationForProgress() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mProgressChannelId, mProgressChannelName, NotificationManager.IMPORTANCE_DEFAULT)
mManager.createNotificationChannel(channel)
}
val progressMax = 100
val progressCurrent = 30
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mProgressChannelId)
.setContentTitle("進(jìn)度通知")
.setContentText("下載中:$progressCurrent%")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_avatar))
// 第3個(gè)參數(shù)indeterminate嚼黔,false表示確定的進(jìn)度细层,比如100,true表示不確定的進(jìn)度唬涧,會(huì)一直顯示進(jìn)度動(dòng)畫(huà)疫赎,直到更新?tīng)顟B(tài)下載完成,或刪除通知
.setProgress(progressMax, progressCurrent, false)
mManager.notify(mProgressNotificationId, mBuilder.build())
}
比較常見(jiàn)的就是下載進(jìn)度了碎节,比如應(yīng)用內(nèi)版本更新捧搞。
通過(guò)setProgress
配置進(jìn)度,接收3個(gè)參數(shù):
- max 最大值
- progress 當(dāng)前進(jìn)度
- indeterminate false表示確定的進(jìn)度狮荔,比如100胎撇,true表示不確定的進(jìn)度,會(huì)一直顯示進(jìn)度動(dòng)畫(huà)殖氏,直到更新?tīng)顟B(tài)完成晚树,或刪除通知
如何更新進(jìn)度往下看。
4.4雅采、更新進(jìn)度條通知
private fun updateNotificationForProgress() {
if (::mBuilder.isInitialized) {
val progressMax = 100
val progressCurrent = 50
// 1.更新進(jìn)度
mBuilder.setContentText("下載中:$progressCurrent%").setProgress(progressMax, progressCurrent, false)
// 2.下載完成
//mBuilder.setContentText("下載完成题涨!").setProgress(0, 0, false)
mManager.notify(mProgressNotificationId, mBuilder.build())
Toast.makeText(this, "已更新進(jìn)度到$progressCurrent%", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "請(qǐng)先發(fā)一條進(jìn)度條通知", Toast.LENGTH_SHORT).show()
}
}
更新進(jìn)度也還是通過(guò)setProgress
,修改當(dāng)前進(jìn)度值即可总滩。
更新分為兩種情況:
- 更新進(jìn)度:修改進(jìn)度值即可
- 下載完成:總進(jìn)度與當(dāng)前進(jìn)度都設(shè)置為0即可纲堵,同時(shí)更新文案
注意:如果有多個(gè)進(jìn)度通知,如何更新到指定的通知闰渔,是通過(guò)NotificationId
匹配的席函。
Author:yechaoa
4.5、大文本通知
private fun createNotificationForBigText() {
val bigText =
"A notification is a message that Android displays outside your app's UI to provide the user with reminders, communication from other people, or other timely information from your app. Users can tap the notification to open your app or take an action directly from the notification."
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mBigTextChannelId, mBigTextChannelName, NotificationManager.IMPORTANCE_DEFAULT)
mManager.createNotificationChannel(channel)
}
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mBigTextChannelId)
.setContentTitle("大文本通知")
.setStyle(NotificationCompat.BigTextStyle().bigText(bigText))
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_avatar))
.setAutoCancel(true)
mManager.notify(mBigTextNotificationId, mBuilder.build())
}
- setStyle(NotificationCompat.BigTextStyle().bigText(bigText))
通知內(nèi)容默認(rèn)最多顯示一行冈涧,超出會(huì)被裁剪茂附,且無(wú)法展開(kāi),在內(nèi)容透出上體驗(yàn)非常不好督弓,展示的內(nèi)容可能無(wú)法吸引用戶(hù)去點(diǎn)擊查看营曼,所以也有了大文本通知的這種方式,
一勞永逸的做法就是無(wú)論內(nèi)容有多少行愚隧,都用大文本的這種方式通知蒂阱,具體展示讓系統(tǒng)自己去適配。
4.6、大圖片通知
private fun createNotificationForBigImage() {
val bigPic = BitmapFactory.decodeResource(resources, R.drawable.ic_big_pic)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mBigImageChannelId, mBigImageChannelName, NotificationManager.IMPORTANCE_DEFAULT)
mManager.createNotificationChannel(channel)
}
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mBigImageChannelId)
.setContentTitle("大圖片通知")
.setContentText("有美女录煤,展開(kāi)看看")
.setStyle(NotificationCompat.BigPictureStyle().bigPicture(bigPic))
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_avatar))
.setAutoCancel(true)
mManager.notify(mBigImageNotificationId, mBuilder.build())
}
與大文本通知方式差不多
- setStyle(NotificationCompat.BigPictureStyle().bigPicture(bigPic))
有一個(gè)注意的點(diǎn)鳄厌,當(dāng)已有多條通知時(shí),默認(rèn)是合并的妈踊,并不是展開(kāi)的了嚎,所以可以通過(guò)setContentText("有美女,展開(kāi)看看")
加個(gè)提示廊营。
- 當(dāng)前應(yīng)用的通知不超過(guò)
3
條歪泳,會(huì)展開(kāi) - 超過(guò)
3
條,通知會(huì)聚合并折疊
4.7露筒、自定義通知
private fun createNotificationForCustom() {
// 適配8.0及以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mCustomChannelId, mCustomChannelName, NotificationManager.IMPORTANCE_DEFAULT)
mManager.createNotificationChannel(channel)
}
// 適配12.0及以上
mFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
// 添加自定義通知view
val views = RemoteViews(packageName, R.layout.layout_notification)
// 添加暫停繼續(xù)事件
val intentStop = Intent(mStopAction)
val pendingIntentStop = PendingIntent.getBroadcast(this@NotificationActivity, 0, intentStop, mFlag)
views.setOnClickPendingIntent(R.id.btn_stop, pendingIntentStop)
// 添加完成事件
val intentDone = Intent(mDoneAction)
val pendingIntentDone = PendingIntent.getBroadcast(this@NotificationActivity, 0, intentDone, mFlag)
views.setOnClickPendingIntent(R.id.btn_done, pendingIntentDone)
// 創(chuàng)建Builder
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mCustomChannelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_avatar))
.setAutoCancel(true)
.setCustomContentView(views)
.setCustomBigContentView(views)// 設(shè)置自定義通知view
// 發(fā)起通知
mManager.notify(mCustomNotificationId, mBuilder.build())
}
假如是一個(gè)播放器的前臺(tái)通知夹囚,默認(rèn)的布局顯示已經(jīng)不滿(mǎn)足需求,那么就用到自定義布局了邀窃。
通過(guò)RemoteViews
構(gòu)建自定義布局view荸哟。因?yàn)镽emoteViews并不是一個(gè)真正的view,它只是一個(gè)view的描述瞬捕,所以事件處理上還是要借助PendingIntent
鞍历。
- setCustomContentView 默認(rèn)布局顯示,即折疊狀態(tài)下的布局
- setCustomBigContentView 展開(kāi)狀態(tài)下的布局
折疊狀態(tài)下肪虎,可能會(huì)展示一些基礎(chǔ)信息劣砍,拿播放器舉例,比如當(dāng)前歌曲名稱(chēng)扇救、歌手刑枝、暫停、繼續(xù)迅腔、下一首等装畅,就差不多展示不下了。 展開(kāi)狀態(tài)下沧烈,就可以提供更多的信息掠兄,比如專(zhuān)輯信息,歌手信息等
這兩種狀態(tài)下默認(rèn)的布局高度:
- 折疊視圖布局锌雀,
48dp
- 展開(kāi)視圖布局蚂夕,
252dp
4.8、更新自定義通知
private fun updateNotificationForCustom() {
// 發(fā)送通知 更新?tīng)顟B(tài)及UI
sendBroadcast(Intent(mStopAction))
}
private fun updateCustomView() {
val views = RemoteViews(packageName, R.layout.layout_notification)
val intentUpdate = Intent(mStopAction)
val pendingIntentUpdate = PendingIntent.getBroadcast(this, 0, intentUpdate, mFlag)
views.setOnClickPendingIntent(R.id.btn_stop, pendingIntentUpdate)
// 根據(jù)狀態(tài)更新UI
if (mIsStop) {
views.setTextViewText(R.id.tv_status, "那些你很冒險(xiǎn)的夢(mèng)-停止播放")
views.setTextViewText(R.id.btn_stop, "繼續(xù)")
mBinding.mbUpdateCustom.text = "繼續(xù)"
} else {
views.setTextViewText(R.id.tv_status, "那些你很冒險(xiǎn)的夢(mèng)-正在播放")
views.setTextViewText(R.id.btn_stop, "暫停")
mBinding.mbUpdateCustom.text = "暫停"
}
mBuilder.setCustomContentView(views).setCustomBigContentView(views)
// 重新發(fā)起通知更新UI腋逆,注意:必須得是同一個(gè)通知id婿牍,即mCustomNotificationId
mManager.notify(mCustomNotificationId, mBuilder.build())
}
上面提到,因?yàn)镽emoteViews并不能直接操作view惩歉,所以可以通過(guò)廣播
的方式等脂,對(duì)該條通知的構(gòu)建配置重新設(shè)置俏蛮,以達(dá)到更新的效果。
遠(yuǎn)古時(shí)期v4包里還有MediaStyle慎菲,AndroidX已經(jīng)下掉了嫁蛇。
5锨并、常用API
API | 描述 |
---|---|
setContentTitle | 標(biāo)題 |
setContentText | 內(nèi)容 |
setSubText | 子標(biāo)題 |
setLargeIcon | 大圖標(biāo) |
setSmallIcon | 小圖標(biāo) |
setContentIntent | 點(diǎn)擊時(shí)意圖 |
setDeleteIntent | 刪除時(shí)意圖 |
setFullScreenIntent | 全屏通知點(diǎn)擊意圖露该,來(lái)電、響鈴 |
setAutoCancel | 點(diǎn)擊自動(dòng)取消 |
setCategory | 通知類(lèi)別第煮,適用“勿擾模式” |
setVisibility | 屏幕可見(jiàn)性解幼,適用“鎖屏狀態(tài)” |
setNumber | 通知項(xiàng)數(shù)量 |
setWhen | 通知時(shí)間 |
setShowWhen | 是否顯示通知時(shí)間 |
setSound | 提示音 |
setVibrate | 震動(dòng) |
setLights | 呼吸燈 |
setPriority | 優(yōu)先級(jí),7.0 |
setTimeoutAfter | 定時(shí)取消包警,8.0及以后 |
setProgress | 進(jìn)度 |
setStyle | 通知樣式撵摆,BigPictureStyle、BigTextStyle害晦、MessagingStyle特铝、InboxStyle、DecoratedCustomViewStyle |
addAction | 通知上的操作壹瘟,10.0 |
setGroup | 分組 |
setColor | 背景顏色 |
6鲫剿、各版本適配
自Android 4.0支持通知以來(lái),幾乎每個(gè)版本都有各種改動(dòng)稻轨,也是苦了開(kāi)發(fā)了...
6.1灵莲、Android 5.0
6.1.1、重要通知
Android 5.0開(kāi)始殴俱,支持重要通知政冻,也稱(chēng)抬頭通知。
6.1.2线欲、鎖屏通知
Android 5.0開(kāi)始明场,支持鎖屏通知,即鎖屏?xí)r顯示在鎖屏桌面李丰。
從8.0開(kāi)始榕堰,用戶(hù)可以通過(guò)通知渠道設(shè)置啟用或禁止鎖屏通知...
6.1.3、勿擾模式
5.0開(kāi)始嫌套,勿擾模式下會(huì)組織所有聲音和震動(dòng)逆屡,8.0以后可以根據(jù)渠道分別設(shè)置。
6.2踱讨、Android 7.0
6.2.1魏蔗、設(shè)置通知優(yōu)先級(jí)
7.1及以下:
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mNormalChannelId)
...
.setPriority(NotificationCompat.PRIORITY_DEFAULT) // 7.0 設(shè)置優(yōu)先級(jí)
8.0及以上改為渠道。
6.2.2痹筛、回復(fù)操作
7.0引入直接回復(fù)操作的功能
private val KEY_TEXT_REPLY = "key_text_reply"
var replyLabel: String = resources.getString(R.string.reply_label)
var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
setLabel(replyLabel)
build()
}
6.2.3莺治、消息通知
7.0開(kāi)始支持消息類(lèi)型通知MessagingStyle
var notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setStyle(NotificationCompat.MessagingStyle("Me")
.setConversationTitle("Team lunch")
.addMessage("Hi", timestamp1, null) // Pass in null for user.
.addMessage("What's up?", timestamp2, "Coworker")
.addMessage("Not much", timestamp3, null)
.addMessage("How about lunch?", timestamp4, "Coworker"))
.build()
從8.0開(kāi)始廓鞠,消息類(lèi)型的展示方式為折疊類(lèi)型...
6.2.4、通知分組
7.0開(kāi)始谣旁,通知支持分組床佳,適用多個(gè)通知的情況。
6.3榄审、Android 8.0
6.3.1砌们、創(chuàng)建通知渠道
創(chuàng)建通知渠道,以及重要性
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(mHighChannelId, mHighChannelName, NotificationManager.IMPORTANCE_HIGH)
mManager.createNotificationChannel(channel)
}
刪除渠道
notificationManager.deleteNotificationChannel(id)
6.3.2搁进、通知角標(biāo)
8.0開(kāi)始浪感,支持設(shè)置通知時(shí)桌面的角標(biāo)是否顯示
val mChannel = NotificationChannel(id, name, importance).apply {
description = descriptionText
setShowBadge(false)
}
6.3.3、通知限制
8.1開(kāi)始饼问,每秒發(fā)出的通知聲音不能超過(guò)一次影兽。
6.3.4、背景顏色
8.0開(kāi)始莱革,設(shè)置通知的背景顏色峻堰。
6.4、Android 10.0
6.4.1盅视、添加操作
mBuilder = NotificationCompat.Builder(this@NotificationActivity, mHighChannelId)
...
.addAction(R.mipmap.ic_avatar, "去看看", pendingIntent)// 通知上的操作
6.4.2捐名、全屏意圖
10.0全屏意圖需要在manifest中申請(qǐng)USE_FULL_SCREEN_INTENT
權(quán)限
6.5、Android 12.0
6.5.1左冬、解鎖設(shè)備
12.0及以上桐筏,可以設(shè)置需要解鎖設(shè)備才能操作:setAuthenticationRequired
val moreSecureNotification = Notification.Builder(context, NotificationListenerVerifierActivity.TAG)
.addAction(...)
// from a lock screen.
.setAuthenticationRequired(true)
.build()
6.5.2、自定義通知
從12.0開(kāi)始拇砰,將不支持完全自定義的通知梅忌,會(huì)提供 Notification.DecoratedCustomViewStyle
替代...
6.5.3、PendingIntent
12.0需要明確設(shè)置flag除破,否則會(huì)有報(bào)錯(cuò):
java.lang.IllegalArgumentException: com.example.imdemo: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
mFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
val intentStop = Intent(mStopAction)
val pendingIntentStop = PendingIntent.getBroadcast(this@NotificationActivity, 0, intentStop, mFlag)
views.setOnClickPendingIntent(R.id.btn_stop, pendingIntentStop)
梳理完適配牧氮,真的覺(jué)得Androider苦
作者:yechaoa
鏈接:https://juejin.cn/post/7113509911887085581
來(lái)源于:稀土掘金