Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
L
location share white
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wanglei
location share white
Commits
8b1c7c11
Commit
8b1c7c11
authored
Oct 31, 2024
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
...
parent
7ed2238e
Show whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
1558 additions
and
1663 deletions
+1558
-1663
build.gradle.kts
app/build.gradle.kts
+1
-0
AdDialog.kt
...src/main/java/com/base/locationsharewhite/ads/AdDialog.kt
+0
-37
AdDisplayUtils.kt
...in/java/com/base/locationsharewhite/ads/AdDisplayUtils.kt
+0
-231
AdmobHelper.kt
.../main/java/com/base/locationsharewhite/ads/AdmobHelper.kt
+0
-128
AdsConfigBean.kt
...ain/java/com/base/locationsharewhite/ads/AdsConfigBean.kt
+18
-0
AdsMgr.kt
app/src/main/java/com/base/locationsharewhite/ads/AdsMgr.kt
+114
-0
AdsShowCallBack.kt
...n/java/com/base/locationsharewhite/ads/AdsShowCallBack.kt
+7
-0
AdsType.kt
app/src/main/java/com/base/locationsharewhite/ads/AdsType.kt
+23
-0
BaseAdMgr.kt
...rc/main/java/com/base/locationsharewhite/ads/BaseAdMgr.kt
+65
-0
AdBannerMgr.kt
...java/com/base/locationsharewhite/ads/admob/AdBannerMgr.kt
+37
-30
AdInsertMgr.kt
...java/com/base/locationsharewhite/ads/admob/AdInsertMgr.kt
+137
-0
AdNativeMgr.kt
...java/com/base/locationsharewhite/ads/admob/AdNativeMgr.kt
+89
-0
AdOpenMgr.kt
...n/java/com/base/locationsharewhite/ads/admob/AdOpenMgr.kt
+136
-0
AdmobEvent.kt
.../java/com/base/locationsharewhite/ads/admob/AdmobEvent.kt
+0
-256
AdmobInterstitialUtils.kt
...se/locationsharewhite/ads/admob/AdmobInterstitialUtils.kt
+0
-192
AdmobNativeUtils.kt
...com/base/locationsharewhite/ads/admob/AdmobNativeUtils.kt
+0
-149
AdmobOpenUtils.kt
...a/com/base/locationsharewhite/ads/admob/AdmobOpenUtils.kt
+0
-161
LimitUtils.kt
.../java/com/base/locationsharewhite/ads/admob/LimitUtils.kt
+109
-0
NativeView.kt
.../java/com/base/locationsharewhite/ads/admob/NativeView.kt
+14
-14
BatteryStatusReceiver.kt
.../com/base/locationsharewhite/fcm/BatteryStatusReceiver.kt
+32
-7
FCMManager.java
...main/java/com/base/locationsharewhite/fcm/FCMManager.java
+1
-2
MsgConfig.kt
...rc/main/java/com/base/locationsharewhite/fcm/MsgConfig.kt
+74
-0
MsgConfigBean.kt
...ain/java/com/base/locationsharewhite/fcm/MsgConfigBean.kt
+9
-0
MsgMgr.kt
app/src/main/java/com/base/locationsharewhite/fcm/MsgMgr.kt
+126
-6
MsgType.kt
app/src/main/java/com/base/locationsharewhite/fcm/MsgType.kt
+25
-0
NotificationUiUtil.kt
...ava/com/base/locationsharewhite/fcm/NotificationUiUtil.kt
+0
-233
PackageStatusReceiver.kt
.../com/base/locationsharewhite/fcm/PackageStatusReceiver.kt
+29
-7
PopupConstObject.kt
.../java/com/base/locationsharewhite/fcm/PopupConstObject.kt
+0
-28
RemoteConfigBean.kt
.../java/com/base/locationsharewhite/fcm/RemoteConfigBean.kt
+18
-0
ScreenStatusReceiver.kt
...a/com/base/locationsharewhite/fcm/ScreenStatusReceiver.kt
+64
-58
TimerManager.kt
...main/java/com/base/locationsharewhite/fcm/TimerManager.kt
+33
-48
ConstConfig.kt
...in/java/com/base/locationsharewhite/helper/ConstConfig.kt
+45
-0
GoogleSdkMgr.kt
...n/java/com/base/locationsharewhite/helper/GoogleSdkMgr.kt
+91
-0
MyApplication.kt
.../java/com/base/locationsharewhite/helper/MyApplication.kt
+62
-0
DeleteNotificationReceiver.kt
...tionsharewhite/notification/DeleteNotificationReceiver.kt
+15
-0
NotificationBean.kt
.../base/locationsharewhite/notification/NotificationBean.kt
+15
-0
NotificationHoverUtils.kt
...locationsharewhite/notification/NotificationHoverUtils.kt
+51
-0
NotificationMgr.kt
...m/base/locationsharewhite/notification/NotificationMgr.kt
+93
-0
StayNotificationService.kt
...ase/locationsharewhite/service/StayNotificationService.kt
+25
-76
No files found.
app/build.gradle.kts
View file @
8b1c7c11
...
...
@@ -78,6 +78,7 @@ dependencies {
implementation
(
"com.google.firebase:firebase-messaging"
)
implementation
(
"com.google.firebase:firebase-analytics-ktx"
)
implementation
(
"com.google.firebase:firebase-crashlytics"
)
implementation
(
"com.google.firebase:firebase-config"
)
//facebook
implementation
(
"com.facebook.android:facebook-android-sdk:[8,9)"
)
...
...
app/src/main/java/com/base/locationsharewhite/ads/AdDialog.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.ads
import
android.animation.ObjectAnimator
import
android.animation.ValueAnimator.INFINITE
import
android.app.AlertDialog
import
android.content.Context
import
android.view.LayoutInflater
import
android.view.animation.LinearInterpolator
import
com.base.locationsharewhite.R
import
com.base.locationsharewhite.databinding.DialogAdPreparingBinding
object
AdDialog
{
fun
Context
.
showAdPreparingDialog
():
AlertDialog
{
val
binding
=
DialogAdPreparingBinding
.
inflate
(
LayoutInflater
.
from
(
this
))
val
dialog
=
AlertDialog
.
Builder
(
this
).
create
()
dialog
.
setView
(
binding
.
root
)
dialog
.
setCancelable
(
false
)
dialog
.
setCanceledOnTouchOutside
(
false
)
dialog
.
show
()
val
params
=
dialog
.
window
?.
attributes
params
?.
width
=
resources
.
getDimensionPixelOffset
(
R
.
dimen
.
dp_200
)
params
?.
height
=
resources
.
getDimensionPixelOffset
(
R
.
dimen
.
dp_146
)
dialog
.
window
?.
attributes
=
params
dialog
.
window
?.
setBackgroundDrawableResource
(
android
.
R
.
color
.
transparent
)
// 创建一个旋转动画
val
rotateAnimator
=
ObjectAnimator
.
ofFloat
(
binding
.
iv
,
"rotation"
,
0f
,
-
360f
)
rotateAnimator
.
setDuration
(
1000
)
// 设置动画持续时间为1000毫秒
rotateAnimator
.
repeatCount
=
INFINITE
rotateAnimator
.
interpolator
=
LinearInterpolator
()
// 设置插值器为线性插值
rotateAnimator
.
start
()
return
dialog
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/AdDisplayUtils.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.pdfreader2.ads
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.LogEx
import
com.base.pdfreader2.ads.AdmobHelper.inter_limit_click
import
com.base.pdfreader2.ads.AdmobHelper.inter_limit_request
import
com.base.pdfreader2.ads.AdmobHelper.inter_limit_show
import
com.base.pdfreader2.ads.AdmobHelper.native_limit_request
import
com.base.pdfreader2.ads.AdmobHelper.native_limit_show
import
com.base.pdfreader2.ads.AdmobHelper.open_limit_click
import
com.base.pdfreader2.ads.AdmobHelper.open_limit_request
import
com.base.pdfreader2.ads.AdmobHelper.open_limit_show
import
java.text.SimpleDateFormat
import
java.util.Calendar
import
java.util.Locale
object
AdDisplayUtils
{
//region open
private
val
open_max_request
=
AppPreferences
.
getInstance
().
getString
(
open_limit_request
,
"15"
).
toInt
()
private
val
open_max_show
=
AppPreferences
.
getInstance
().
getString
(
open_limit_show
,
"10"
).
toInt
()
private
val
open_max_click
=
AppPreferences
.
getInstance
().
getString
(
open_limit_click
,
"1"
).
toInt
()
fun
incrementOpenRequestCount
()
{
currentOpenRequest
+=
1
}
fun
incrementOpenShow
()
{
currentOpenShow
+=
1
}
fun
incrementClickShow
()
{
currentOpenClick
+=
1
}
//当前开屏请求次数
private
var
currentOpenRequest
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentOpenRequest_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentOpenRequest_${currentDate()}"
,
value
,
true
)
}
//当前开屏展示次数
private
var
currentOpenShow
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentOpenShow_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentOpenShow_${currentDate()}"
,
value
,
true
)
}
//当前开屏点击次数
private
var
currentOpenClick
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentOpenClick_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentOpenClick_${currentDate()}"
,
value
,
true
)
}
fun
shouldShowOpenAd
():
Boolean
{
if
(
currentOpenRequest
>
open_max_request
)
{
LogEx
.
logDebug
(
TAG
,
"currentOpenRequest=$currentOpenRequest open_max_request=$open_max_request"
)
EventUtils
.
event
(
"ad_limit"
,
"currentOpenRequest=$currentOpenRequest open_max_request=$open_max_request"
)
return
false
}
if
(
currentOpenShow
>
open_max_show
)
{
LogEx
.
logDebug
(
TAG
,
"currentOpenShow=$currentOpenShow open_max_show=$open_max_show"
)
EventUtils
.
event
(
"ad_limit"
,
"currentOpenShow=$currentOpenShow open_max_show=$open_max_show"
)
return
false
}
if
(
currentOpenClick
>
open_max_click
)
{
LogEx
.
logDebug
(
TAG
,
"currentOpenClick=$currentOpenClick open_max_click=$open_max_click"
)
EventUtils
.
event
(
"ad_limit"
,
"currentOpenClick=$currentOpenClick open_max_click=$open_max_click"
)
return
false
}
return
true
}
//endregion
//region inter
private
val
inter_max_request
=
AppPreferences
.
getInstance
().
getString
(
inter_limit_request
,
"15"
).
toInt
()
private
val
inter_max_show
=
AppPreferences
.
getInstance
().
getString
(
inter_limit_show
,
"10"
).
toInt
()
private
val
inter_max_click
=
AppPreferences
.
getInstance
().
getString
(
inter_limit_click
,
"1"
).
toInt
()
fun
incrementInterRequestCount
()
{
currentInterRequest
+=
1
}
fun
incrementInterShowCount
()
{
currentInterShow
+=
1
}
fun
incrementInterClickCount
()
{
currentInterClick
+=
1
}
//当前插页请求次数
private
var
currentInterRequest
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentInterRequest_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentInterRequest_${currentDate()}"
,
value
,
true
)
}
//当前插页展示次数
private
var
currentInterShow
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentInterShow_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentInterShow_${currentDate()}"
,
value
,
true
)
}
//当前插页点击次数
private
var
currentInterClick
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentInterClick_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentInterClick_${currentDate()}"
,
value
,
true
)
}
fun
shouldShowInterAd
():
Boolean
{
if
(
currentInterRequest
>
inter_max_request
)
{
LogEx
.
logDebug
(
TAG
,
"currentInterRequest=$currentInterRequest inter_max_request=$inter_max_request"
)
EventUtils
.
event
(
"ad_limit"
,
"currentInterRequest=$currentInterRequest inter_max_request=$inter_max_request"
)
return
false
}
if
(
currentInterShow
>
inter_max_show
)
{
LogEx
.
logDebug
(
TAG
,
"currentInterShow=$currentInterShow inter_max_show=$inter_max_show"
)
EventUtils
.
event
(
"ad_limit"
,
"currentInterShow=$currentInterShow inter_max_show=$inter_max_show"
)
return
false
}
if
(
currentInterClick
>
inter_max_click
)
{
LogEx
.
logDebug
(
TAG
,
"currentInterClick=$currentInterClick inter_max_click=$inter_max_click"
)
EventUtils
.
event
(
"ad_limit"
,
"currentInterClick=$currentInterClick inter_max_click=$inter_max_click"
)
return
false
}
return
true
}
//endregion
//region native
private
val
native_max_request
=
AppPreferences
.
getInstance
().
getString
(
native_limit_request
,
"15"
).
toInt
()
private
val
native_max_show
=
AppPreferences
.
getInstance
().
getString
(
native_limit_show
,
"10"
).
toInt
()
private
val
native_max_click
=
AppPreferences
.
getInstance
().
getString
(
native_limit_show
,
"1"
).
toInt
()
fun
incrementNativeRequestCount
()
{
currentNativeRequest
+=
1
}
fun
incrementNativeShowCount
()
{
currentNativeShow
+=
1
}
fun
incrementNativeClickCount
()
{
currentNativeClick
+=
1
}
private
var
currentNativeRequest
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentNativeRequest_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentNativeRequest_${currentDate()}"
,
value
,
true
)
}
private
var
currentNativeShow
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentNativeShow_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentNativeShow_${currentDate()}"
,
value
,
true
)
}
private
var
currentNativeClick
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"currentNativeClick_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"currentNativeClick_${currentDate()}"
,
value
,
true
)
}
fun
shouldShowNative
():
Boolean
{
if
(
currentNativeRequest
>
native_max_request
)
{
LogEx
.
logDebug
(
TAG
,
"currentNativeRequest=$currentNativeRequest native_max_request=$native_max_request"
)
EventUtils
.
event
(
"ad_limit"
,
"currentNativeRequest=$currentNativeRequest native_max_request=$native_max_request"
)
return
false
}
if
(
currentNativeShow
>
native_max_show
)
{
LogEx
.
logDebug
(
TAG
,
"currentNativeShow=$currentNativeShow native_max_show=$native_max_show"
)
EventUtils
.
event
(
"ad_limit"
,
"currentNativeShow=$currentNativeShow native_max_show=$native_max_show"
)
return
false
}
if
(
currentNativeClick
>
native_max_click
)
{
LogEx
.
logDebug
(
TAG
,
"currentNativeClick=$currentNativeClick native_max_click=$native_max_click"
)
EventUtils
.
event
(
"ad_limit"
,
"currentNativeClick=$currentNativeClick native_max_click=$native_max_click"
)
return
false
}
return
true
}
//endregion
private
val
TAG
=
"AdDisplayUtils"
private
fun
currentDate
():
String
{
val
dateFormat
=
SimpleDateFormat
(
"yyyy-MM-dd"
,
Locale
.
getDefault
())
val
currentDate
=
Calendar
.
getInstance
().
time
return
dateFormat
.
format
(
currentDate
)
}
}
app/src/main/java/com/base/locationsharewhite/ads/AdmobHelper.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.pdfreader2.ads
import
android.app.Activity
import
com.base.locationsharewhite.ads.admob.AdmobInterstitialUtils
import
com.base.locationsharewhite.ads.admob.AdmobNativeUtils
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.utils.AppPreferences
import
com.google.android.gms.ads.MobileAds
import
java.util.concurrent.atomic.AtomicBoolean
object
AdmobHelper
{
//开屏限制
const
val
open_limit_request
=
"open_limit_request"
const
val
open_limit_show
=
"open_limit_show"
const
val
open_limit_click
=
"open_limit_click"
//插页限制
const
val
inter_limit_request
=
"inter_limit_request"
const
val
inter_limit_show
=
"inter_limit_show"
const
val
inter_limit_click
=
"inter_limit_click"
//原生广告限制
const
val
native_limit_request
=
"native_limit_request"
const
val
native_limit_show
=
"native_limit_show"
const
val
native_limit_click
=
"native_limit_click"
//开屏加载ad时间
val
open_ad_loading
=
"open_ad_loading"
var
isAdInit
=
AtomicBoolean
(
false
)
fun
initAdmobAd
(
activity
:
Activity
)
{
MobileAds
.
initialize
(
MyApplication
.
context
)
{
initializationStatus
->
isAdInit
.
set
(
true
)
EventUtils
.
event
(
"AdmobInit"
,
"AdmobInit"
)
AdmobNativeUtils
.
loadNativeAd
()
AdmobInterstitialUtils
.
loadInterstitialAd
(
activity
)
}
}
//上次展示广告时间关闭赋值,通用开屏和插页
var
lastShowedOnHiddenTime
=
0L
get
()
{
return
AppPreferences
.
getInstance
().
getLong
(
"lastShowedOnHiddenTime"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"lastShowedOnHiddenTime"
,
value
,
true
)
}
/**
* 通用广告条件判断
*/
fun
canCommonShowAd
():
Boolean
{
val
interval
=
AppPreferences
.
getInstance
().
getString
(
"ad_interval"
,
"10"
).
toInt
()
if
(
System
.
currentTimeMillis
()
-
lastShowedOnHiddenTime
<
interval
*
1000L
)
{
return
false
}
return
true
}
//上次scan展示ad时间
var
lastScanShowAd
=
0L
get
()
{
return
AppPreferences
.
getInstance
().
getLong
(
"lastScanShowAd"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"lastScanShowAd"
,
value
,
true
)
}
//是否显示扫描功能ad
fun
isShowScanInter
():
Boolean
{
val
interval
=
AppPreferences
.
getInstance
().
getString
(
"scan_ad_interval"
,
"10"
).
toInt
()
return
System
.
currentTimeMillis
()
-
lastScanShowAd
>
interval
*
1000L
}
//上次打开文档展示ad时间
var
lastOpenDocumentShowAd
=
0L
get
()
{
return
AppPreferences
.
getInstance
().
getLong
(
"lastOpenDocumentShowAd"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"lastOpenDocumentShowAd"
,
value
,
true
)
}
//打开文档是否展示广告
fun
isShowOpenDocumentInter
():
Boolean
{
val
interval
=
AppPreferences
.
getInstance
().
getString
(
"open_document_ad_interval"
,
"10"
).
toInt
()
val
openStatus
=
AppPreferences
.
getInstance
().
getString
(
"open_document_ad_status"
,
"1"
).
toInt
()
return
openStatus
==
1
&&
System
.
currentTimeMillis
()
-
lastOpenDocumentShowAd
>
interval
*
1000L
}
var
lastCloseDocumentShowAd
=
0L
get
()
{
return
AppPreferences
.
getInstance
().
getLong
(
"lastCloseDocumentShowAd"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"lastCloseDocumentShowAd"
,
value
,
true
)
}
fun
isShowCloseDocumentInter
():
Boolean
{
val
interval
=
AppPreferences
.
getInstance
().
getString
(
"close_document_ad_interval"
,
"10"
).
toInt
()
return
System
.
currentTimeMillis
()
-
lastCloseDocumentShowAd
>
interval
*
1000L
}
fun
isShowCloseDocument
():
Boolean
{
val
status
=
AppPreferences
.
getInstance
().
getString
(
"close_document_ad_show"
,
"0"
).
toInt
()
return
status
==
1
}
fun
isShowRvNativeAd
():
Boolean
{
val
status
=
AppPreferences
.
getInstance
().
getString
(
"rv_native_ad_show"
,
"0"
).
toInt
()
return
status
==
1
}
fun
isBackShowAd
():
Boolean
{
val
status
=
AppPreferences
.
getInstance
().
getString
(
"is_back_show_ad"
,
"0"
).
toInt
()
return
status
==
1
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/AdsConfigBean.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.ads
/**
* 广告限制配置
*
* @property isInBlackList 是否在黑名单
* @property numDisplayLimit 展示次数限制 -1为不限制,0为彻底关闭显示
* @property numRequestLimit 请求次数限制 -1为不限制,0为彻底关闭显示
* @property numClickLimit 点击次数限制 -1为不限制,0为彻底关闭显示
* @property timeInterval 广告间隔时间
*/
data class
AdsConfigBean
(
var
isInBlackList
:
Boolean
=
false
,
var
numDisplayLimit
:
Int
=
-
1
,
var
numRequestLimit
:
Int
=
-
1
,
var
numClickLimit
:
Int
=
-
1
,
var
timeInterval
:
Int
=
1
)
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/AdsMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.ads
import
android.app.Activity
import
android.content.Context
import
android.view.ViewGroup
import
com.base.locationsharewhite.ads.admob.AdBannerMgr
import
com.base.locationsharewhite.ads.admob.AdInsertMgr
import
com.base.locationsharewhite.ads.admob.AdNativeMgr
import
com.example.mydemo.strategy.ads.admob.AdOpenMgr
import
com.google.android.gms.ads.MobileAds
import
com.google.android.gms.ads.initialization.AdapterStatus
/**
* 广告管理类
*/
object
AdsMgr
{
private
val
adOpenMgr
by
lazy
{
AdOpenMgr
()
}
private
val
adInsertMgr
by
lazy
{
AdInsertMgr
()
}
private
val
adNativeMgr
by
lazy
{
AdNativeMgr
()
}
private
val
adBannerMgr
by
lazy
{
AdBannerMgr
()
}
/**
* 是否初始化
*/
var
isInit
=
false
private
set
/**
* 广告配置项目
*/
var
adsConfigBean
:
AdsConfigBean
?
=
null
private
set
/**
* Init 初始化
*
* @param context 这里最好是appContext,因为是耗时操作,等它初始化完毕马上加载开屏和插屏广告
*/
fun
init
(
context
:
Context
,
adsConfigBean
:
AdsConfigBean
)
{
if
(
adsConfigBean
.
isInBlackList
)
return
this
.
adsConfigBean
=
adsConfigBean
MobileAds
.
initialize
(
context
)
{
val
readyAdapter
=
it
.
adapterStatusMap
.
entries
.
find
{
entry
->
entry
.
value
.
initializationState
==
AdapterStatus
.
State
.
READY
}
isInit
=
readyAdapter
!=
null
if
(
isInit
)
{
//成功初始化就提前预加载开屏广告和插页广告
adOpenMgr
.
loadAd
(
context
)
adInsertMgr
.
loadAd
(
context
)
}
}
}
/**
* 展示开屏广告
*
* @param activity 当前页面
* @param showCallBack 展示回调
*/
fun
showOpen
(
activity
:
Activity
,
showCallBack
:
AdsShowCallBack
?
=
null
)
{
if
(!
isInit
||
adsConfigBean
?.
isInBlackList
!=
false
)
{
showCallBack
?.
failed
()
return
}
adOpenMgr
.
show
(
activity
,
showCallBack
)
}
/**
* 展示插屏广告
*
* @param activity 当前页面
* @param showCallBack 展示回调
*/
fun
showInsert
(
activity
:
Activity
,
showCallBack
:
AdsShowCallBack
?
=
null
)
{
if
(!
isInit
||
adsConfigBean
?.
isInBlackList
!=
false
)
{
showCallBack
?.
failed
()
return
}
adInsertMgr
.
show
(
activity
,
showCallBack
)
}
/**
* 展示原生广告
*
* @param parent 需要展示广告的父布局容器
* @param layout 原生广告布局 ,这里传入的layout要和com.example.mydemo.strategy.ads.admob.NativeView里的id一致
*/
fun
showNative
(
parent
:
ViewGroup
,
layout
:
Int
)
{
if
(!
isInit
||
adsConfigBean
?.
isInBlackList
!=
false
)
return
adNativeMgr
.
show
(
parent
,
layout
)
}
/**
* 展示banner广告
*
* @param parent 展示广告的父布局容器
*/
fun
showBanner
(
parent
:
ViewGroup
)
{
if
(!
isInit
||
adsConfigBean
?.
isInBlackList
!=
false
)
return
adBannerMgr
.
show
(
parent
)
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/AdsShowCallBack.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.ads
abstract
class
AdsShowCallBack
{
open
fun
show
()
{}
abstract
fun
close
()
abstract
fun
failed
()
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/AdsType.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.ads
/**
* 广告类型
* 0=开屏广告、1=插屏广告、2=原生广告、3=Banner横幅广告
*/
@JvmInline
value
class
AdsType
private
constructor
(
val
value
:
Int
)
{
companion
object
{
val
OPEN
=
AdsType
(
0
)
val
INSERT
=
AdsType
(
1
)
val
NATIVE
=
AdsType
(
2
)
val
BANNER
=
AdsType
(
3
)
fun
from
(
adsType
:
Int
):
AdsType
{
return
when
(
adsType
)
{
OPEN
.
value
->
OPEN
INSERT
.
value
->
INSERT
NATIVE
.
value
->
NATIVE
else
->
BANNER
}
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/BaseAdMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.ads
import
android.app.Activity
import
android.content.Context
import
java.lang.ref.WeakReference
/**
* 特定广告管理基类
* @param T 缓存广告的类
*/
abstract
class
BaseAdMgr
<
T
>
{
/**
* 广告展示回调
*/
protected
var
showCallBack
:
AdsShowCallBack
?
=
null
/**
* 当前缓存的广告
*/
protected
var
currentAd
:
T
?
=
null
/**
* 是否正在缓存加载广告
*/
protected
var
loadingAd
:
Boolean
=
false
/**
* 是否正在显示广告
*/
protected
var
showingAd
:
Boolean
=
false
/**
* 用于保存引用现有页面,在此页面显示广告(因为要等待广告加载完毕)
*/
protected
var
activityRef
:
WeakReference
<
Activity
>?
=
null
/**
* 上一次的缓存成功时间
*/
protected
var
lastTime
:
Long
=
0
/**
* 预加载广告
*
* @param context 加载所用的上下文,一般使用appContext
*/
abstract
fun
loadAd
(
context
:
Context
)
/**
* 广告显示
*
* @param activity 当前页面
*/
abstract
fun
show
(
activity
:
Activity
,
showCallBack
:
AdsShowCallBack
?
=
null
)
/**
* 预加载的缓存超时判断
*
* @return true:没有超时 false:超时需要重新加载
*/
abstract
fun
adAvailable
():
Boolean
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/Ad
mobBannerColla
.kt
→
app/src/main/java/com/base/locationsharewhite/ads/admob/Ad
BannerMgr
.kt
View file @
8b1c7c11
package
com.base.locationsharewhite.ads.admob
import
android.content.Context
import
android.os.Bundle
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
com.base.locationsharewhite.BuildConfig
import
com.base.locationsharewhite.helper.ConfigHelper
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.LogEx
import
com.base.locationsharewhite.helper.ConstConfig
import
com.google.ads.mediation.admob.AdMobAdapter
import
com.google.android.gms.ads.AdListener
import
com.google.android.gms.ads.AdRequest
...
...
@@ -15,43 +11,47 @@ import com.google.android.gms.ads.AdSize
import
com.google.android.gms.ads.AdView
import
java.util.UUID
object
AdmobBannerUtils
{
/**
*banner广告加载显示管理类
*/
class
AdBannerMgr
{
private
const
val
TAG
=
"AdmobBannerUtils"
private
var
adView
:
AdView
?
=
null
private
var
listener
:
ViewTreeObserver
.
OnGlobalLayoutListener
?
=
null
fun
showCollapsibleBannerAd
(
context
:
Context
,
parent
:
ViewGroup
,
adClose
:
(()
->
Unit
)?
=
null
)
{
val
isShowBanner
=
AppPreferences
.
getInstance
().
getString
(
"isShowBanner"
,
"0"
).
toInt
()
if
(
isShowBanner
==
0
)
{
return
}
parent
.
removeAllViews
()
fun
show
(
parent
:
ViewGroup
)
{
if
(
adView
!=
null
)
{
adView
?.
destroy
()
}
if
(!
LimitUtils
.
isAdShow
())
{
adView
=
null
adView
=
AdView
(
context
)
// adView?.apply {
// onPaidEventListener = com.base.locationsharewhite.ads.admob.AdmobEvent.EventOnPaidEventListener(this)
return
}
adView
=
AdView
(
parent
.
context
)
adView
?.
tag
=
"CollapsibleBannerAd"
// val list = parent.children
// list.forEach {
// if (it.tag != "zhanweitu") {
// parent.removeView(it)
// }
// }
parent
.
addView
(
adView
)
listener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
val
screenPixelDensity
=
context
.
resources
.
displayMetrics
.
density
val
screenPixelDensity
=
parent
.
context
.
resources
.
displayMetrics
.
density
val
adWidth
=
(
parent
.
width
/
screenPixelDensity
).
toInt
()
val
adSize
=
AdSize
.
getCurrentOrientationAnchoredAdaptiveBannerAdSize
(
context
,
adWidth
)
adView
?.
adUnitId
=
if
(
BuildConfig
.
DEBUG
)
ConfigHelper
.
bannerAdmobIdTest
else
ConfigHelper
.
bannerAdmobId
val
adSize
=
AdSize
.
getCurrentOrientationAnchoredAdaptiveBannerAdSize
(
parent
.
context
,
adWidth
)
adView
?.
adUnitId
=
ConstConfig
.
bannerAdId
adView
?.
setAdSize
(
adSize
)
load
CollapsibleBanner
(
adClose
)
load
Ad
(
parent
)
parent
.
viewTreeObserver
.
removeOnGlobalLayoutListener
(
listener
)
}
parent
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
listener
)
}
private
fun
loadCollapsibleBanner
(
adClose
:
(()
->
Unit
)?)
{
fun
loadAd
(
parent
:
ViewGroup
)
{
val
extras
=
Bundle
()
extras
.
putString
(
"collapsible"
,
"bottom"
)
extras
.
putString
(
"collapsible_request_id"
,
UUID
.
randomUUID
().
toString
())
...
...
@@ -60,20 +60,27 @@ object AdmobBannerUtils {
adView
?.
adListener
=
object
:
AdListener
()
{
override
fun
onAdLoaded
()
{
LogEx
.
logDebug
(
TAG
,
"onAdLoaded"
)
}
override
fun
onAdOpened
()
{
LogEx
.
logDebug
(
TAG
,
"onAdOpened"
)
}
override
fun
onAdClosed
()
{
super
.
onAdClosed
()
LogEx
.
logDebug
(
TAG
,
"onAdClosed"
)
adClose
?.
invoke
()
// val removeList = arrayListOf<View>()
// parent.children.forEach {
// if (it.tag != "CollapsibleBannerAd") {
// removeList.add(it)
// }
// }
// removeList.forEach {
// parent.removeView(it)
// }
}
}
adView
?.
loadAd
(
adRequest
)
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdInsertMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.ads.admob
import
android.app.Activity
import
android.content.Context
import
com.base.locationsharewhite.helper.ConstConfig
import
com.example.mydemo.strategy.ads.AdsShowCallBack
import
com.example.mydemo.strategy.ads.BaseAdMgr
import
com.google.android.gms.ads.AdError
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.FullScreenContentCallback
import
com.google.android.gms.ads.LoadAdError
import
com.google.android.gms.ads.interstitial.InterstitialAd
import
com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
import
java.lang.ref.WeakReference
/**
*插屏广告加载显示管理类
*/
class
AdInsertMgr
:
BaseAdMgr
<
InterstitialAd
>()
{
private
var
lastOpenDate
:
Long
=
0
private
val
adLoadCallback
=
object
:
InterstitialAdLoadCallback
()
{
override
fun
onAdLoaded
(
ad
:
InterstitialAd
)
{
super
.
onAdLoaded
(
ad
)
// 开屏广告加载成功
currentAd
=
ad
loadingAd
=
false
lastTime
=
System
.
currentTimeMillis
()
val
ac
=
activityRef
?.
get
()
if
(
ac
!=
null
)
{
show
(
ac
)
}
}
override
fun
onAdFailedToLoad
(
loadAdError
:
LoadAdError
)
{
super
.
onAdFailedToLoad
(
loadAdError
)
// 广告加载失败
// 官方不建议在此回调中重新加载广告
// 如果确实需要,则必须限制最大重试次数,避免在网络受限的情况下连续多次请求
loadingAd
=
false
if
(
activityRef
!=
null
&&
!
showingAd
&&
showCallBack
!=
null
)
{
showCallBack
?.
failed
()
showCallBack
=
null
}
}
}
override
fun
loadAd
(
context
:
Context
)
{
if
(!
loadingAd
&&
LimitUtils
.
isAdShow
())
{
loadingAd
=
true
//计数
LimitUtils
.
addRequestNum
()
InterstitialAd
.
load
(
context
,
ConstConfig
.
insertAdId
,
AdRequest
.
Builder
().
build
(),
adLoadCallback
)
}
}
override
fun
show
(
activity
:
Activity
,
showCallBack
:
AdsShowCallBack
?)
{
if
(
activity
.
isFinishing
||
activity
.
isDestroyed
||
!
LimitUtils
.
isAdShow
()
||
LimitUtils
.
isIntervalLimited
(
lastOpenDate
)
)
{
showCallBack
?.
failed
()
return
}
if
(
showingAd
)
{
// 开屏广告正在展示
return
}
if
(
showCallBack
!=
null
&&
this
.
showCallBack
!=
showCallBack
)
this
.
showCallBack
=
showCallBack
if
(
currentAd
==
null
||
!
adAvailable
())
{
//缓存广告过期
currentAd
=
null
if
(
activityRef
==
null
)
{
activityRef
=
WeakReference
(
activity
)
// 开屏广告不可用或者缓存超时过期,重新加载
loadAd
(
activity
.
applicationContext
)
}
else
{
activityRef
=
null
this
.
showCallBack
?.
failed
()
this
.
showCallBack
=
null
}
return
}
currentAd
?.
run
{
fullScreenContentCallback
=
object
:
FullScreenContentCallback
()
{
override
fun
onAdShowedFullScreenContent
()
{
super
.
onAdShowedFullScreenContent
()
lastOpenDate
=
System
.
currentTimeMillis
()
// 广告展示
currentAd
=
null
activityRef
=
null
this
@AdInsertMgr
.
showCallBack
?.
show
()
//计数
LimitUtils
.
addDisplayNum
()
}
override
fun
onAdFailedToShowFullScreenContent
(
adError
:
AdError
)
{
super
.
onAdFailedToShowFullScreenContent
(
adError
)
// 广告展示失败,清空缓存数据,重新加载
showingAd
=
false
currentAd
=
null
activityRef
=
null
this
@AdInsertMgr
.
showCallBack
?.
failed
()
this
@AdInsertMgr
.
showCallBack
=
null
}
override
fun
onAdDismissedFullScreenContent
()
{
super
.
onAdDismissedFullScreenContent
()
// 广告关闭,清空缓存数据,重新加载
showingAd
=
false
this
@AdInsertMgr
.
showCallBack
?.
close
()
this
@AdInsertMgr
.
showCallBack
=
null
loadAd
(
activity
.
applicationContext
)
}
override
fun
onAdClicked
()
{
super
.
onAdClicked
()
//计数
LimitUtils
.
addClickNum
()
}
}
showingAd
=
true
show
(
activity
)
}
}
override
fun
adAvailable
()
=
((
System
.
currentTimeMillis
()
-
lastTime
)
/
1000
/
60
).
toInt
()
<
30
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdNativeMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.ads.admob
import
android.content.Context
import
android.view.ViewGroup
import
androidx.core.view.isVisible
import
com.base.locationsharewhite.helper.ConstConfig
import
com.example.mydemo.strategy.ads.admob.NativeView
import
com.google.android.gms.ads.AdListener
import
com.google.android.gms.ads.AdLoader
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.LoadAdError
import
com.google.android.gms.ads.nativead.NativeAd
import
com.google.android.gms.ads.nativead.NativeAdOptions
import
java.util.concurrent.ConcurrentLinkedDeque
/**
*原生广告加载显示管理类
*/
class
AdNativeMgr
{
/**
* 上一次的缓存成功时间
*/
protected
var
lastTime
:
Long
=
0
/**
* 原生广告缓存队列
*/
private
val
cacheItems
=
ConcurrentLinkedDeque
<
NativeAd
>()
fun
loadAd
(
context
:
Context
,
parent
:
ViewGroup
?
=
null
,
layout
:
Int
?
=
null
)
{
val
adLoader
=
AdLoader
.
Builder
(
context
,
ConstConfig
.
nativeAdId
)
.
forNativeAd
{
nativeAd
->
cacheItems
.
offer
(
nativeAd
)
lastTime
=
System
.
currentTimeMillis
()
if
(
parent
!=
null
&&
layout
!=
null
)
show
(
parent
,
layout
)
}
.
withAdListener
(
object
:
AdListener
()
{
override
fun
onAdFailedToLoad
(
error
:
LoadAdError
)
{
}
override
fun
onAdClicked
()
{
super
.
onAdClicked
()
}
override
fun
onAdClosed
()
{
super
.
onAdClosed
()
}
})
.
withNativeAdOptions
(
NativeAdOptions
.
Builder
()
// .setAdChoicesPlacement(NativeAdOptions.ADCHOICES_TOP_RIGHT)
// .setMediaAspectRatio(NativeAdOptions.NATIVE_MEDIA_ASPECT_RATIO_SQUARE)
.
build
()
)
.
build
()
// Load AdMob native advanced ads
adLoader
.
loadAds
(
AdRequest
.
Builder
().
build
(),
1
)
}
fun
show
(
parent
:
ViewGroup
,
layout
:
Int
)
{
if
(!
LimitUtils
.
isAdShow
())
{
cacheItems
.
clear
()
return
}
val
nativeAd
=
cacheItems
.
peek
()
if
(
nativeAd
==
null
||
!
adAvailable
())
{
//缓存过期了就清空
cacheItems
.
clear
()
loadAd
(
parent
.
context
.
applicationContext
,
parent
,
layout
)
return
}
NativeView
(
parent
.
context
,
layout
).
run
{
parent
.
removeAllViews
()
setNativeAd
(
nativeAd
)
parent
.
addView
(
this
)
parent
.
isVisible
=
true
}
loadAd
(
parent
.
context
.
applicationContext
)
}
fun
adAvailable
():
Boolean
{
return
((
System
.
currentTimeMillis
()
-
lastTime
)
/
1000
/
60
).
toInt
()
<
30
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdOpenMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.ads.admob
import
android.app.Activity
import
android.content.Context
import
com.base.locationsharewhite.ads.admob.LimitUtils
import
com.base.locationsharewhite.helper.ConstConfig
import
com.example.mydemo.strategy.ads.AdsShowCallBack
import
com.example.mydemo.strategy.ads.BaseAdMgr
import
com.google.android.gms.ads.AdError
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.FullScreenContentCallback
import
com.google.android.gms.ads.LoadAdError
import
com.google.android.gms.ads.appopen.AppOpenAd
import
java.lang.ref.WeakReference
/**
* 开屏广告加载显示管理类
*/
class
AdOpenMgr
:
BaseAdMgr
<
AppOpenAd
>()
{
private
var
lastOpenDate
:
Long
=
0
private
val
adLoadCallback
=
object
:
AppOpenAd
.
AppOpenAdLoadCallback
()
{
override
fun
onAdLoaded
(
appOpenAd
:
AppOpenAd
)
{
super
.
onAdLoaded
(
appOpenAd
)
// 开屏广告加载成功
currentAd
=
appOpenAd
loadingAd
=
false
lastTime
=
System
.
currentTimeMillis
()
val
ac
=
activityRef
?.
get
()
if
(
ac
!=
null
)
{
show
(
ac
)
}
}
override
fun
onAdFailedToLoad
(
loadAdError
:
LoadAdError
)
{
super
.
onAdFailedToLoad
(
loadAdError
)
// 开屏广告加载失败
// 官方不建议在此回调中重新加载广告
// 如果确实需要,则必须限制最大重试次数,避免在网络受限的情况下连续多次请求
loadingAd
=
false
if
(
activityRef
!=
null
&&
!
showingAd
&&
showCallBack
!=
null
)
{
showCallBack
?.
failed
()
showCallBack
=
null
}
}
}
override
fun
loadAd
(
context
:
Context
)
{
if
(!
loadingAd
&&
LimitUtils
.
isAdShow
())
{
loadingAd
=
true
//计数
LimitUtils
.
addRequestNum
()
AppOpenAd
.
load
(
context
,
ConstConfig
.
openAdId
,
AdRequest
.
Builder
().
build
(),
adLoadCallback
)
}
}
override
fun
show
(
activity
:
Activity
,
showCallBack
:
AdsShowCallBack
?)
{
if
(
activity
.
isFinishing
||
activity
.
isDestroyed
||
!
LimitUtils
.
isAdShow
()
||
LimitUtils
.
isIntervalLimited
(
lastOpenDate
)
)
{
showCallBack
?.
failed
()
return
}
if
(
showingAd
)
{
// 开屏广告正在展示
return
}
if
(
showCallBack
!=
null
&&
this
.
showCallBack
!=
showCallBack
)
this
.
showCallBack
=
showCallBack
if
(
currentAd
==
null
||
!
adAvailable
())
{
//缓存广告过期
currentAd
=
null
if
(
activityRef
==
null
)
{
activityRef
=
WeakReference
(
activity
)
// 开屏广告不可用或者缓存超时过期,重新加载
loadAd
(
activity
.
applicationContext
)
}
else
{
activityRef
=
null
this
.
showCallBack
?.
failed
()
this
.
showCallBack
=
null
}
return
}
currentAd
?.
run
{
fullScreenContentCallback
=
object
:
FullScreenContentCallback
()
{
override
fun
onAdShowedFullScreenContent
()
{
super
.
onAdShowedFullScreenContent
()
lastOpenDate
=
System
.
currentTimeMillis
()
// 广告展示
currentAd
=
null
activityRef
=
null
this
@AdOpenMgr
.
showCallBack
?.
show
()
//计数
LimitUtils
.
addDisplayNum
()
}
override
fun
onAdFailedToShowFullScreenContent
(
adError
:
AdError
)
{
super
.
onAdFailedToShowFullScreenContent
(
adError
)
// 广告展示失败,清空缓存数据,重新加载
showingAd
=
false
currentAd
=
null
activityRef
=
null
this
@AdOpenMgr
.
showCallBack
?.
failed
()
this
@AdOpenMgr
.
showCallBack
=
null
}
override
fun
onAdDismissedFullScreenContent
()
{
super
.
onAdDismissedFullScreenContent
()
// 广告关闭,清空缓存数据,重新加载
showingAd
=
false
this
@AdOpenMgr
.
showCallBack
?.
close
()
this
@AdOpenMgr
.
showCallBack
=
null
loadAd
(
activity
.
applicationContext
)
}
override
fun
onAdClicked
()
{
super
.
onAdClicked
()
//计数
LimitUtils
.
addClickNum
()
}
}
showingAd
=
true
show
(
activity
)
}
}
override
fun
adAvailable
()
=
((
System
.
currentTimeMillis
()
-
lastTime
)
/
1000
/
60
).
toInt
()
<
30
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdmobEvent.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.ads.admob
import
android.app.Activity
import
android.os.Bundle
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.utils.LogEx
import
com.facebook.appevents.AppEventsConstants
import
com.facebook.appevents.AppEventsLogger
import
com.google.android.gms.ads.AdValue
import
com.google.android.gms.ads.OnPaidEventListener
import
com.google.android.gms.ads.ResponseInfo
import
com.google.android.gms.ads.appopen.AppOpenAd
import
com.google.android.gms.ads.interstitial.InterstitialAd
import
com.google.android.gms.ads.nativead.NativeAd
import
com.google.android.gms.ads.rewarded.RewardedAd
import
com.google.firebase.analytics.FirebaseAnalytics
import
com.google.firebase.analytics.ktx.analytics
import
com.google.firebase.ktx.Firebase
import
org.json.JSONObject
object
AdmobEvent
{
private
val
TAG
=
"AdmobEvent"
fun
pullAd
(
responseInfo
:
ResponseInfo
?,
adUnit
:
String
,
error
:
String
?
=
null
,
reqId
:
String
?
=
null
)
{
val
obj
=
JSONObject
()
if
(
responseInfo
!=
null
)
{
val
response
=
responseInfo
.
adapterResponses
.
getOrNull
(
0
)
if
(
response
!=
null
)
{
obj
.
put
(
"source"
,
response
.
adSourceName
)
val
credentials
=
mapOf
(
"placementid"
to
response
.
credentials
.
get
(
"placementid"
),
"appid"
to
response
.
credentials
.
get
(
"appid"
),
"pubid"
to
response
.
credentials
.
get
(
"pubid"
)
)
obj
.
put
(
"credentials"
,
credentials
.
toString
())
}
obj
.
put
(
"session_id"
,
responseInfo
.
responseId
)
}
obj
.
put
(
"networkname"
,
responseInfo
?.
mediationAdapterClassName
)
obj
.
put
(
"ad_unit"
,
adUnit
)
obj
.
put
(
"req_id"
,
reqId
)
if
(
error
==
null
)
{
obj
.
put
(
"status"
,
"1"
)
}
else
{
obj
.
put
(
"errMsg"
,
error
)
obj
.
put
(
"status"
,
"2"
)
}
LogEx
.
logDebug
(
TAG
,
"obj=$obj"
)
EventUtils
.
event
(
"ad_pull"
,
ext
=
obj
)
}
private
val
taichiPref
by
lazy
{
MyApplication
.
context
.
getSharedPreferences
(
"TaichiTroasCache"
,
0
)
}
private
val
taichiSharedPreferencesEditor
by
lazy
{
taichiPref
.
edit
()
}
class
EventOnPaidEventListener
(
private
val
ad
:
Any
?)
:
OnPaidEventListener
{
override
fun
onPaidEvent
(
adValue
:
AdValue
)
{
val
valueMicros
=
adValue
.
valueMicros
val
currencyCode
=
adValue
.
currencyCode
val
precision
=
adValue
.
precisionType
val
obj
=
JSONObject
()
obj
.
put
(
"valueMicros"
,
valueMicros
)
obj
.
put
(
"currencyCode"
,
currencyCode
)
obj
.
put
(
"precision"
,
precision
)
Firebase
.
analytics
.
logEvent
(
"ad_price"
,
Bundle
().
apply
{
putDouble
(
"valueMicros"
,
valueMicros
/
1000000.0
)
})
val
params
=
Bundle
()
val
currentImpressionRevenue
=
adValue
.
valueMicros
.
toDouble
()
/
1000000.0
params
.
putDouble
(
FirebaseAnalytics
.
Param
.
VALUE
,
currentImpressionRevenue
)
params
.
putString
(
FirebaseAnalytics
.
Param
.
CURRENCY
,
"USD"
)
val
precisionType
=
when
(
adValue
.
precisionType
)
{
0
->
"UNKNOWN"
1
->
"ESTIMATED"
2
->
"PUBLISHER_PROVIDED"
3
->
"PRECISE"
else
->
"Invalid"
}
params
.
putString
(
"precisionType"
,
precisionType
)
Firebase
.
analytics
.
logEvent
(
"Ad_Impression_Revenue"
,
params
)
val
previousTaichiTroasCache
=
taichiPref
.
getFloat
(
"TaichiTroasCache"
,
0f
)
val
currentTaichiTroasCache
=
(
previousTaichiTroasCache
+
currentImpressionRevenue
).
toFloat
()
if
(
currentTaichiTroasCache
>=
0.01
)
{
//如果超过0.01就触发一次tROAS taichi事件
val
roasbundle
=
Bundle
()
roasbundle
.
putDouble
(
FirebaseAnalytics
.
Param
.
VALUE
,
currentTaichiTroasCache
.
toDouble
()
)
roasbundle
.
putString
(
FirebaseAnalytics
.
Param
.
CURRENCY
,
"USD"
)
Firebase
.
analytics
.
logEvent
(
"Total_Ads_Revenue_001"
,
roasbundle
)
taichiSharedPreferencesEditor
.
putFloat
(
"TaichiTroasCache"
,
0f
)
//重新清零,开始计算
val
logger
=
AppEventsLogger
.
newLogger
(
MyApplication
.
context
)
val
parameters
=
Bundle
()
parameters
.
putString
(
AppEventsConstants
.
EVENT_PARAM_CURRENCY
,
"USD"
)
logger
.
logEvent
(
"ad_value"
,
currentTaichiTroasCache
.
toDouble
(),
parameters
)
}
else
{
taichiSharedPreferencesEditor
.
putFloat
(
"TaichiTroasCache"
,
currentTaichiTroasCache
)
}
taichiSharedPreferencesEditor
.
commit
()
var
key
=
"ad_price"
when
(
ad
)
{
is
AppOpenAd
->
{
val
adUnitId
=
ad
.
adUnitId
val
loadedAdapterResponseInfo
=
ad
.
responseInfo
.
loadedAdapterResponseInfo
val
adSourceName
=
loadedAdapterResponseInfo
?.
adSourceName
val
adSourceId
=
loadedAdapterResponseInfo
?.
adSourceId
val
adSourceInstanceName
=
loadedAdapterResponseInfo
?.
adSourceInstanceName
val
adSourceInstanceId
=
loadedAdapterResponseInfo
?.
adSourceInstanceId
val
sessionId
=
ad
.
responseInfo
.
responseId
val
extras
=
ad
.
responseInfo
.
responseExtras
val
mediationGroupName
=
extras
.
getString
(
"mediation_group_name"
)
val
mediationABTestName
=
extras
.
getString
(
"mediation_ab_test_name"
)
val
mediationABTestVariant
=
extras
.
getString
(
"mediation_ab_test_variant"
)
obj
.
put
(
"ad_unit"
,
"openAd"
)
obj
.
put
(
"adUnitId"
,
adUnitId
)
obj
.
put
(
"adSourceName"
,
adSourceName
)
obj
.
put
(
"adSourceId"
,
adSourceId
)
obj
.
put
(
"adSourceInstanceName"
,
adSourceInstanceName
)
obj
.
put
(
"adSourceInstanceId"
,
adSourceInstanceId
)
obj
.
put
(
"mediationGroupName"
,
mediationGroupName
)
obj
.
put
(
"mediationABTestName"
,
mediationABTestName
)
obj
.
put
(
"mediationABTestVariant"
,
mediationABTestVariant
)
obj
.
put
(
"session_id"
,
sessionId
)
}
is
InterstitialAd
->
{
val
adUnitId
=
ad
.
adUnitId
val
loadedAdapterResponseInfo
=
ad
.
responseInfo
.
loadedAdapterResponseInfo
val
adSourceName
=
loadedAdapterResponseInfo
?.
adSourceName
val
adSourceId
=
loadedAdapterResponseInfo
?.
adSourceId
val
adSourceInstanceName
=
loadedAdapterResponseInfo
?.
adSourceInstanceName
val
adSourceInstanceId
=
loadedAdapterResponseInfo
?.
adSourceInstanceId
val
sessionId
=
ad
.
responseInfo
.
responseId
val
extras
=
ad
.
responseInfo
.
responseExtras
val
mediationGroupName
=
extras
.
getString
(
"mediation_group_name"
)
val
mediationABTestName
=
extras
.
getString
(
"mediation_ab_test_name"
)
val
mediationABTestVariant
=
extras
.
getString
(
"mediation_ab_test_variant"
)
obj
.
put
(
"ad_unit"
,
"interAd"
)
obj
.
put
(
"adUnitId"
,
adUnitId
)
obj
.
put
(
"adSourceName"
,
adSourceName
)
obj
.
put
(
"adSourceId"
,
adSourceId
)
obj
.
put
(
"adSourceInstanceName"
,
adSourceInstanceName
)
obj
.
put
(
"adSourceInstanceId"
,
adSourceInstanceId
)
obj
.
put
(
"mediationGroupName"
,
mediationGroupName
)
obj
.
put
(
"mediationABTestName"
,
mediationABTestName
)
obj
.
put
(
"mediationABTestVariant"
,
mediationABTestVariant
)
obj
.
put
(
"session_id"
,
sessionId
)
}
is
RewardedAd
->
{
val
loadedAdapterResponseInfo
=
ad
.
responseInfo
.
loadedAdapterResponseInfo
val
adSourceName
=
loadedAdapterResponseInfo
?.
adSourceName
val
adSourceId
=
loadedAdapterResponseInfo
?.
adSourceId
val
adSourceInstanceName
=
loadedAdapterResponseInfo
?.
adSourceInstanceName
val
adSourceInstanceId
=
loadedAdapterResponseInfo
?.
adSourceInstanceId
val
sessionId
=
ad
.
responseInfo
.
responseId
val
extras
=
ad
.
responseInfo
.
responseExtras
val
mediationGroupName
=
extras
.
getString
(
"mediation_group_name"
)
val
mediationABTestName
=
extras
.
getString
(
"mediation_ab_test_name"
)
val
mediationABTestVariant
=
extras
.
getString
(
"mediation_ab_test_variant"
)
obj
.
put
(
"adSourceName"
,
adSourceName
)
obj
.
put
(
"adSourceId"
,
adSourceId
)
obj
.
put
(
"adSourceInstanceName"
,
adSourceInstanceName
)
obj
.
put
(
"adSourceInstanceId"
,
adSourceInstanceId
)
obj
.
put
(
"mediationGroupName"
,
mediationGroupName
)
obj
.
put
(
"mediationABTestName"
,
mediationABTestName
)
obj
.
put
(
"mediationABTestVariant"
,
mediationABTestVariant
)
obj
.
put
(
"session_id"
,
sessionId
)
}
is
NativeAd
->
{
key
=
"ad_price_native"
val
loadedAdapterResponseInfo
=
ad
.
responseInfo
?.
loadedAdapterResponseInfo
val
adSourceName
=
loadedAdapterResponseInfo
?.
adSourceName
val
adSourceId
=
loadedAdapterResponseInfo
?.
adSourceId
val
adSourceInstanceName
=
loadedAdapterResponseInfo
?.
adSourceInstanceName
val
adSourceInstanceId
=
loadedAdapterResponseInfo
?.
adSourceInstanceId
val
sessionId
=
ad
.
responseInfo
?.
responseId
val
extras
=
ad
.
responseInfo
?.
responseExtras
val
mediationGroupName
=
extras
?.
getString
(
"mediation_group_name"
)
val
mediationABTestName
=
extras
?.
getString
(
"mediation_ab_test_name"
)
val
mediationABTestVariant
=
extras
?.
getString
(
"mediation_ab_test_variant"
)
obj
.
put
(
"adUnitId"
,
"nativeAd"
)
obj
.
put
(
"adSourceName"
,
adSourceName
)
obj
.
put
(
"adSourceId"
,
adSourceId
)
obj
.
put
(
"adSourceInstanceName"
,
adSourceInstanceName
)
obj
.
put
(
"adSourceInstanceId"
,
adSourceInstanceId
)
obj
.
put
(
"mediationGroupName"
,
mediationGroupName
)
obj
.
put
(
"mediationABTestName"
,
mediationABTestName
)
obj
.
put
(
"mediationABTestVariant"
,
mediationABTestVariant
)
obj
.
put
(
"session_id"
,
sessionId
)
}
}
EventUtils
.
event
(
key
,
ext
=
obj
)
}
}
fun
clickAd
(
responseInfo
:
ResponseInfo
?,
adUnit
:
String
)
{
val
response
=
responseInfo
?.
adapterResponses
?.
getOrNull
(
0
)
val
obj
=
JSONObject
()
obj
.
put
(
"source"
,
response
?.
adSourceName
)
obj
.
put
(
"ad_unit"
,
adUnit
)
val
credentials
=
mapOf
(
"placementid"
to
response
?.
credentials
?.
get
(
"placementid"
),
"appid"
to
response
?.
credentials
?.
get
(
"appid"
),
"pubid"
to
response
?.
credentials
?.
get
(
"pubid"
)
)
obj
.
put
(
"credentials"
,
credentials
.
toString
())
obj
.
put
(
"session_id"
,
responseInfo
?.
responseId
)
obj
.
put
(
"networkname"
,
responseInfo
?.
mediationAdapterClassName
)
if
(
adUnit
!=
"nativeAd"
)
{
EventUtils
.
event
(
"ad_click"
,
ext
=
obj
)
}
else
{
EventUtils
.
event
(
"bigimage_ad_click"
,
ext
=
obj
)
}
}
fun
showAd
(
responseInfo
:
ResponseInfo
?,
adUnit
:
String
,
activity
:
Activity
?
=
null
)
{
val
response
=
responseInfo
?.
adapterResponses
?.
getOrNull
(
0
)
val
obj
=
JSONObject
()
obj
.
put
(
"source"
,
response
?.
adSourceName
)
obj
.
put
(
"ad_unit"
,
adUnit
)
obj
.
put
(
"networkname"
,
responseInfo
?.
mediationAdapterClassName
)
val
credentials
=
mapOf
(
"placementid"
to
response
?.
credentials
?.
get
(
"placementid"
),
"appid"
to
response
?.
credentials
?.
get
(
"appid"
),
"pubid"
to
response
?.
credentials
?.
get
(
"pubid"
)
)
obj
.
put
(
"credentials"
,
credentials
.
toString
())
obj
.
put
(
"session_id"
,
responseInfo
?.
responseId
)
obj
.
put
(
"from"
,
activity
?.
javaClass
?.
simpleName
)
if
(
adUnit
!=
"nativeAd"
)
{
EventUtils
.
event
(
"ad_show"
,
ext
=
obj
)
}
else
{
EventUtils
.
event
(
"bigimage_ad_show"
,
ext
=
obj
)
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdmobInterstitialUtils.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.ads.admob
import
android.app.Activity
import
android.app.Dialog
import
android.widget.Toast
import
com.base.locationsharewhite.BuildConfig
import
com.base.locationsharewhite.ads.AdDialog.showAdPreparingDialog
import
com.base.locationsharewhite.ads.admob.AdmobEvent.clickAd
import
com.base.locationsharewhite.ads.admob.AdmobEvent.pullAd
import
com.base.locationsharewhite.ads.admob.AdmobEvent.showAd
import
com.base.locationsharewhite.helper.ConfigHelper
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.pdfreader2.ads.AdDisplayUtils
import
com.base.pdfreader2.ads.AdmobHelper.lastShowedOnHiddenTime
import
com.google.android.gms.ads.AdError
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.FullScreenContentCallback
import
com.google.android.gms.ads.LoadAdError
import
com.google.android.gms.ads.interstitial.InterstitialAd
import
com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
import
org.json.JSONObject
import
java.util.UUID
object
AdmobInterstitialUtils
{
private
var
interAd
:
InterstitialAd
?
=
null
private
var
interLoadTime
=
Long
.
MAX_VALUE
private
var
adLastDisplayTime
:
Long
=
0
private
val
mRequest
=
AdRequest
.
Builder
().
build
()
private
fun
isAdExpired
():
Boolean
{
return
System
.
currentTimeMillis
()
-
interLoadTime
>
1000
*
60
*
60
}
fun
showInterstitialAd
(
activity
:
Activity
,
isReLoadAd
:
Boolean
=
false
,
isShowDialog
:
Boolean
=
true
,
onHidden
:
((
showed
:
Boolean
)
->
Unit
)?
=
null
)
{
if
(
activity
.
isFinishing
||
activity
.
isDestroyed
)
{
return
}
if
(
isAdExpired
())
{
val
obj2
=
JSONObject
()
obj2
.
put
(
"ad_unit"
,
"interAd"
)
EventUtils
.
event
(
"ad_expire"
,
ext
=
obj2
)
interAd
=
null
loadInterstitialAd
(
activity
)
onHidden
?.
invoke
(
false
)
return
}
if
(!
AdDisplayUtils
.
shouldShowInterAd
())
{
onHidden
?.
invoke
(
false
)
return
}
val
obj1
=
JSONObject
()
obj1
.
put
(
"ad_unit"
,
"interAd"
)
EventUtils
.
event
(
"ad_prepare_show"
,
ext
=
obj1
)
if
(
interAd
!=
null
)
{
var
dialog
:
Dialog
?
=
null
if
(!
activity
.
isFinishing
&&
!
activity
.
isDestroyed
)
{
dialog
=
activity
.
showAdPreparingDialog
()
}
displayInterstitialAd
(
activity
,
dialog
,
onHidden
)
}
else
{
showAdDialogAndLoadInterstitial
(
activity
,
isReLoadAd
,
isShowDialog
,
onHidden
)
}
}
fun
loadInterstitialAd
(
activity
:
Activity
,
onLoad
:
(()
->
Unit
)?
=
null
)
{
if
(
interAd
!=
null
)
{
onLoad
?.
invoke
()
return
}
if
(!
AdDisplayUtils
.
shouldShowInterAd
())
{
onLoad
?.
invoke
()
return
}
val
reqId
=
UUID
.
randomUUID
().
toString
()
val
obj
=
JSONObject
()
obj
.
put
(
"req_id"
,
reqId
)
obj
.
put
(
"ad_type"
,
"interAd"
)
obj
.
put
(
"from"
,
activity
.
javaClass
.
simpleName
)
EventUtils
.
event
(
"ad_pull_start"
,
ext
=
obj
)
InterstitialAd
.
load
(
activity
,
if
(
BuildConfig
.
DEBUG
)
ConfigHelper
.
interAdmobIdTest
else
ConfigHelper
.
interAdmobId
,
mRequest
,
object
:
InterstitialAdLoadCallback
()
{
override
fun
onAdFailedToLoad
(
p0
:
LoadAdError
)
{
interAd
=
null
onLoad
?.
invoke
()
pullAd
(
p0
.
responseInfo
,
"interAd"
,
p0
.
message
,
reqId
=
reqId
)
if
(
BuildConfig
.
DEBUG
)
{
Toast
.
makeText
(
MyApplication
.
context
,
"拉取失败"
+
p0
.
message
,
Toast
.
LENGTH_SHORT
).
show
()
}
}
override
fun
onAdLoaded
(
ad
:
InterstitialAd
)
{
interAd
=
ad
onLoad
?.
invoke
()
interLoadTime
=
System
.
currentTimeMillis
()
pullAd
(
ad
.
responseInfo
,
"interAd"
,
reqId
=
reqId
)
ad
.
onPaidEventListener
=
AdmobEvent
.
EventOnPaidEventListener
(
ad
)
AdDisplayUtils
.
incrementInterRequestCount
()
}
})
}
private
fun
showAdDialogAndLoadInterstitial
(
activity
:
Activity
,
isReLoadAd
:
Boolean
,
isShowDialog
:
Boolean
,
onHidden
:
((
showed
:
Boolean
)
->
Unit
)?
)
{
if
(!
isShowDialog
)
{
onHidden
?.
invoke
(
false
)
return
}
var
mDialog
:
Dialog
?
=
null
if
(!
activity
.
isFinishing
&&
!
activity
.
isDestroyed
)
{
mDialog
=
activity
.
showAdPreparingDialog
()
mDialog
.
show
()
}
loadInterstitialAd
(
activity
)
{
mDialog
?.
dismiss
()
if
(!
isReLoadAd
)
{
showInterstitialAd
(
activity
,
true
,
false
)
{
onHidden
?.
invoke
(
it
)
}
}
}
if
(
isReLoadAd
)
{
mDialog
?.
dismiss
()
onHidden
?.
invoke
(
false
)
}
}
private
fun
displayInterstitialAd
(
activity
:
Activity
,
dialog
:
Dialog
?
=
null
,
onHidden
:
((
showed
:
Boolean
)
->
Unit
)?
=
null
)
{
val
thisInterAd
=
interAd
interAd
=
null
thisInterAd
?.
fullScreenContentCallback
=
object
:
FullScreenContentCallback
()
{
override
fun
onAdClicked
()
{
clickAd
(
thisInterAd
?.
responseInfo
,
"interAd"
)
AdDisplayUtils
.
incrementInterClickCount
()
}
override
fun
onAdDismissedFullScreenContent
()
{
dialog
?.
dismiss
()
interAd
=
null
onHidden
?.
invoke
(
true
)
loadInterstitialAd
(
activity
)
lastShowedOnHiddenTime
=
System
.
currentTimeMillis
()
}
override
fun
onAdFailedToShowFullScreenContent
(
p0
:
AdError
)
{
dialog
?.
dismiss
()
interAd
=
null
onHidden
?.
invoke
(
false
)
loadInterstitialAd
(
activity
)
}
override
fun
onAdShowedFullScreenContent
()
{
dialog
?.
dismiss
()
showAd
(
thisInterAd
?.
responseInfo
,
"interAd"
,
activity
)
AdDisplayUtils
.
incrementInterShowCount
()
adLastDisplayTime
=
System
.
currentTimeMillis
()
/
1000
}
}
thisInterAd
?.
show
(
activity
)
}
fun
haveReadAd
():
Boolean
{
return
interAd
!=
null
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdmobNativeUtils.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.ads.admob
import
android.app.Activity
import
android.view.ViewGroup
import
androidx.core.view.isVisible
import
com.base.locationsharewhite.BuildConfig
import
com.base.locationsharewhite.R
import
com.base.locationsharewhite.ads.admob.AdmobEvent.clickAd
import
com.base.locationsharewhite.ads.admob.AdmobEvent.pullAd
import
com.base.locationsharewhite.ads.admob.AdmobEvent.showAd
import
com.base.locationsharewhite.helper.ConfigHelper
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.utils.LogEx
import
com.base.pdfreader2.ads.AdDisplayUtils
import
com.google.android.gms.ads.AdListener
import
com.google.android.gms.ads.AdLoader
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.LoadAdError
import
com.google.android.gms.ads.nativead.NativeAd
import
org.json.JSONObject
import
java.util.UUID
object
AdmobNativeUtils
{
private
const
val
TAG
=
"AdmobNativeUtils"
private
var
nativeAd
:
NativeAd
?
=
null
private
var
isLoading
=
false
private
var
nativeLoadTime
=
Long
.
MAX_VALUE
private
var
loadingListener
:
(()
->
Unit
)?
=
null
private
val
mRequest
=
AdRequest
.
Builder
().
build
()
var
onAdLoaded
:
(()
->
Unit
)?
=
null
fun
loadNativeAd
()
{
if
(
nativeAd
!=
null
)
{
return
}
if
(
isLoading
)
{
return
}
isLoading
=
true
if
(!
AdDisplayUtils
.
shouldShowNative
())
{
return
}
val
reqId
=
UUID
.
randomUUID
().
toString
()
val
obj
=
JSONObject
()
obj
.
put
(
"req_id"
,
reqId
)
obj
.
put
(
"ad_type"
,
"nativeAd"
)
val
adLoader
=
AdLoader
.
Builder
(
MyApplication
.
context
,
if
(
BuildConfig
.
DEBUG
)
ConfigHelper
.
nativeAdmobIdTest
else
ConfigHelper
.
nativeAdmobId
).
forNativeAd
{
nativeLoadTime
=
System
.
currentTimeMillis
()
nativeAd
=
it
it
.
setOnPaidEventListener
(
AdmobEvent
.
EventOnPaidEventListener
(
it
))
LogEx
.
logDebug
(
TAG
,
"nativeAd=${nativeAd.toString()}"
)
isLoading
=
false
loadingListener
?.
invoke
()
loadingListener
=
null
pullAd
(
it
.
responseInfo
,
"nativeAd"
,
reqId
=
reqId
)
}.
withAdListener
(
object
:
AdListener
()
{
override
fun
onAdLoaded
()
{
super
.
onAdLoaded
()
onAdLoaded
?.
invoke
()
onAdLoaded
=
null
AdDisplayUtils
.
incrementNativeRequestCount
()
}
override
fun
onAdClicked
()
{
clickAd
(
nativeAd
?.
responseInfo
,
"nativeAd"
)
AdDisplayUtils
.
incrementNativeClickCount
()
}
override
fun
onAdFailedToLoad
(
p0
:
LoadAdError
)
{
LogEx
.
logDebug
(
TAG
,
"onAdFailedToLoad=${p0.message}"
)
nativeAd
=
null
isLoading
=
false
pullAd
(
p0
.
responseInfo
,
"nativeAd"
,
p0
.
message
,
reqId
=
reqId
)
// Log.e("MXL", "NativeAdFailedToLoad: " + p0.message)
}
}).
build
()
adLoader
.
loadAd
(
mRequest
)
}
fun
showNativeAd
(
activity
:
Activity
?,
parent
:
ViewGroup
,
layout
:
Int
=
R
.
layout
.
layout_admob_native_custom
)
{
val
obj
=
JSONObject
()
obj
.
put
(
"ad_unit"
,
"nativeAd"
)
EventUtils
.
event
(
"ad_prepare_show_native"
,
ext
=
obj
)
if
(!
AdDisplayUtils
.
shouldShowNative
())
{
return
}
loadingListener
=
{
if
(
System
.
currentTimeMillis
()
-
nativeLoadTime
<=
1000
*
60
*
60
)
{
nativeAd
?.
let
{
NativeView
(
parent
.
context
,
layout
).
run
{
parent
.
removeAllViews
()
setNativeAd
(
it
)
parent
.
addView
(
this
)
parent
.
isVisible
=
true
showAd
(
nativeAd
?.
responseInfo
,
"nativeAd"
,
activity
)
}
}
}
nativeAd
=
null
loadNativeAd
()
}
if
(
nativeAd
==
null
)
{
loadNativeAd
()
val
obj2
=
JSONObject
()
obj2
.
put
(
"reason"
,
"no_ad"
)
obj2
.
put
(
"ad_unit"
,
"nativeAd"
)
EventUtils
.
event
(
"ad_show_error"
,
ext
=
obj2
)
}
else
{
loadingListener
?.
invoke
()
loadingListener
=
null
}
}
fun
showReadyNativeAd
(
activity
:
Activity
?,
readyNativeAd
:
NativeAd
?,
parent
:
ViewGroup
,
layout
:
Int
=
R
.
layout
.
layout_admob_native_custom
)
{
readyNativeAd
?.
let
{
NativeView
(
parent
.
context
,
layout
).
run
{
parent
.
removeAllViews
()
setNativeAd
(
it
)
parent
.
addView
(
this
)
parent
.
isVisible
=
true
showAd
(
nativeAd
?.
responseInfo
,
"nativeAd"
,
activity
)
}
}
}
fun
onDestroy
()
{
nativeAd
?.
destroy
()
nativeAd
=
null
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/AdmobOpenUtils.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.ads.admob
import
android.app.Activity
import
com.base.locationsharewhite.BuildConfig
import
com.base.locationsharewhite.ads.admob.AdmobEvent.clickAd
import
com.base.locationsharewhite.ads.admob.AdmobEvent.pullAd
import
com.base.locationsharewhite.ads.admob.AdmobEvent.showAd
import
com.base.locationsharewhite.helper.ConfigHelper
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.utils.LogEx
import
com.base.pdfreader2.ads.AdDisplayUtils
import
com.base.pdfreader2.ads.AdmobHelper.lastShowedOnHiddenTime
import
com.google.android.gms.ads.AdError
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.FullScreenContentCallback
import
com.google.android.gms.ads.LoadAdError
import
com.google.android.gms.ads.appopen.AppOpenAd
import
org.json.JSONObject
import
java.util.UUID
object
AdmobOpenUtils
{
private
const
val
TAG
=
"AdmobOpenUtils"
private
val
mRequest
=
AdRequest
.
Builder
().
build
()
private
var
openLoadTime
=
Long
.
MAX_VALUE
private
var
mOpenAd
:
AppOpenAd
?
=
null
private
fun
isAdExpired
():
Boolean
{
return
System
.
currentTimeMillis
()
-
openLoadTime
>
1000
*
60
*
60
}
fun
haveReadAd
():
Boolean
{
return
mOpenAd
!=
null
}
fun
loadAppOpenAd
(
onLoad
:
((
loaded
:
Boolean
)
->
Unit
)?
=
null
)
{
if
(
mOpenAd
!=
null
)
{
onLoad
?.
invoke
(
true
)
return
}
if
(!
AdDisplayUtils
.
shouldShowOpenAd
())
{
onLoad
?.
invoke
(
false
)
return
}
val
reqId
=
UUID
.
randomUUID
().
toString
()
val
obj
=
JSONObject
()
obj
.
put
(
"req_id"
,
reqId
)
obj
.
put
(
"ad_type"
,
"openAd"
)
EventUtils
.
event
(
"ad_pull_start"
,
ext
=
obj
)
AppOpenAd
.
load
(
MyApplication
.
context
,
if
(
BuildConfig
.
DEBUG
)
ConfigHelper
.
openAdmobIdTest
else
ConfigHelper
.
openAdmobId
,
mRequest
,
object
:
AppOpenAd
.
AppOpenAdLoadCallback
()
{
override
fun
onAdLoaded
(
ad
:
AppOpenAd
)
{
LogEx
.
logDebug
(
TAG
,
"onAdLoaded"
)
openLoadTime
=
System
.
currentTimeMillis
()
mOpenAd
=
ad
onLoad
?.
invoke
(
true
)
pullAd
(
ad
.
responseInfo
,
"openAd"
,
reqId
=
reqId
)
ad
.
onPaidEventListener
=
AdmobEvent
.
EventOnPaidEventListener
(
ad
)
AdDisplayUtils
.
incrementOpenRequestCount
()
}
override
fun
onAdFailedToLoad
(
p0
:
LoadAdError
)
{
LogEx
.
logDebug
(
TAG
,
"LoadAdError ${p0.message}"
)
mOpenAd
=
null
onLoad
?.
invoke
(
false
)
pullAd
(
p0
.
responseInfo
,
"openAd"
,
p0
.
message
,
reqId
=
reqId
)
}
})
}
fun
showAppOpenAd
(
activity
:
Activity
,
isRetry
:
Boolean
=
false
,
showBefore
:
((
flag
:
Boolean
)
->
Unit
)?
=
null
,
onHidden
:
((
showed
:
Boolean
)
->
Unit
)?
=
null
)
{
if
(
activity
.
isFinishing
||
activity
.
isDestroyed
)
{
LogEx
.
logDebug
(
TAG
,
"activity isDestroyed"
)
return
}
if
(!
AdDisplayUtils
.
shouldShowOpenAd
())
{
onHidden
?.
invoke
(
false
)
return
}
if
(
isAdExpired
())
{
LogEx
.
logDebug
(
TAG
,
"openLoadTime out time"
)
mOpenAd
=
null
loadAppOpenAd
()
onHidden
?.
invoke
(
false
)
val
obj2
=
JSONObject
()
obj2
.
put
(
"ad_unit"
,
"openAd"
)
EventUtils
.
event
(
"ad_expire"
,
ext
=
obj2
)
return
}
if
(!
isRetry
)
{
val
obj1
=
JSONObject
()
obj1
.
put
(
"ad_unit"
,
"openAd"
)
EventUtils
.
event
(
"ad_prepare_show"
,
ext
=
obj1
)
LogEx
.
logDebug
(
TAG
,
"open ad_prepare_show"
)
}
if
(
mOpenAd
!=
null
)
{
LogEx
.
logDebug
(
TAG
,
"mOpenAd!=null"
)
val
thisMOpenAd
=
mOpenAd
mOpenAd
=
null
thisMOpenAd
?.
fullScreenContentCallback
=
object
:
FullScreenContentCallback
()
{
override
fun
onAdClicked
()
{
clickAd
(
thisMOpenAd
?.
responseInfo
,
"openAd"
)
AdDisplayUtils
.
incrementClickShow
()
}
override
fun
onAdDismissedFullScreenContent
()
{
mOpenAd
=
null
onHidden
?.
invoke
(
true
)
loadAppOpenAd
()
lastShowedOnHiddenTime
=
System
.
currentTimeMillis
()
}
override
fun
onAdFailedToShowFullScreenContent
(
p0
:
AdError
)
{
mOpenAd
=
null
onHidden
?.
invoke
(
false
)
loadAppOpenAd
()
val
obj
=
JSONObject
()
obj
.
put
(
"reason"
,
p0
.
message
)
obj
.
put
(
"code"
,
p0
.
code
)
obj
.
put
(
"ad_unit"
,
"openAd"
)
EventUtils
.
event
(
"ad_show_error"
,
ext
=
obj
)
}
override
fun
onAdShowedFullScreenContent
()
{
showBefore
?.
invoke
(
true
)
showAd
(
thisMOpenAd
?.
responseInfo
,
"openAd"
,
activity
)
AdDisplayUtils
.
incrementOpenShow
()
}
}
thisMOpenAd
?.
show
(
activity
)
}
else
{
LogEx
.
logDebug
(
TAG
,
"mOpenAd=null"
)
loadAppOpenAd
{
if
(
mOpenAd
!=
null
)
{
showAppOpenAd
(
activity
,
true
,
showBefore
,
onHidden
)
}
else
{
val
obj
=
JSONObject
()
obj
.
put
(
"reason"
,
"no_ad"
)
obj
.
put
(
"ad_unit"
,
"openAd"
)
EventUtils
.
event
(
"ad_show_error"
,
ext
=
obj
)
onHidden
?.
invoke
(
false
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/LimitUtils.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.ads.admob
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.KotlinExt.toFormatTime4
import
com.example.mydemo.strategy.ads.AdsMgr
/**
* 控制广告计数与判断显示条件
*
*/
object
LimitUtils
{
const
val
NUM_DISPLAY
=
"numDisplayLimit"
const
val
NUM_REQUEST
=
"numRequestLimit"
const
val
NUM_CLICK
=
"numClickLimit"
const
val
SAVE_DATE
=
"SAVE_DATE"
/**
* 保存的时间,用来判断是否是当天,不是当天要重置计数次数
*/
private
var
saveDate
get
()
=
AppPreferences
.
getInstance
()
.
getString
(
SAVE_DATE
,
System
.
currentTimeMillis
().
toFormatTime4
())
set
(
value
)
=
AppPreferences
.
getInstance
().
put
(
SAVE_DATE
,
value
)
/**
* 广告请求是否到达限制
*/
private
inline
val
isRequestLimited
:
Boolean
get
()
{
val
maxCount
=
AdsMgr
.
adsConfigBean
?.
numRequestLimit
?:
100
return
maxCount
>
-
1
&&
AppPreferences
.
getInstance
()
.
getInt
(
NUM_REQUEST
,
0
)
>=
maxCount
}
/**
* 广告展示是否到达限制
*/
private
inline
val
isDisplayLimited
:
Boolean
get
()
{
val
maxCount
=
AdsMgr
.
adsConfigBean
?.
numDisplayLimit
?:
100
return
maxCount
>
-
1
&&
AppPreferences
.
getInstance
()
.
getInt
(
NUM_DISPLAY
,
0
)
>=
maxCount
}
/**
* 广告点击是否到达限制
*/
private
inline
val
isClickLimited
:
Boolean
get
()
{
val
maxCount
=
AdsMgr
.
adsConfigBean
?.
numClickLimit
?:
100
return
maxCount
>
-
1
&&
AppPreferences
.
getInstance
()
.
getInt
(
NUM_CLICK
,
0
)
>=
maxCount
}
/**
* 是否显示广告
*
* @return true or false
*/
fun
isAdShow
():
Boolean
{
val
currentDate
=
System
.
currentTimeMillis
().
toFormatTime4
()
if
(
saveDate
!=
currentDate
)
{
//如果已经不是今天了,就重置个数
saveDate
=
currentDate
AppPreferences
.
getInstance
().
put
(
NUM_DISPLAY
,
0
)
AppPreferences
.
getInstance
().
put
(
NUM_REQUEST
,
0
)
AppPreferences
.
getInstance
().
put
(
NUM_CLICK
,
0
)
}
return
!(
isDisplayLimited
||
isClickLimited
||
isRequestLimited
)
}
private
fun
addNum
(
key
:
String
)
{
val
currentDate
=
System
.
currentTimeMillis
().
toFormatTime4
()
if
(
saveDate
!=
currentDate
)
{
//如果已经不是今天了,就重置个数
saveDate
=
currentDate
AppPreferences
.
getInstance
().
put
(
key
,
1
)
return
}
AppPreferences
.
getInstance
()
.
put
(
key
,
(
AppPreferences
.
getInstance
().
getInt
(
key
,
0
)
+
1
))
}
fun
addDisplayNum
()
{
addNum
(
NUM_DISPLAY
)
}
fun
addRequestNum
()
{
addNum
(
NUM_REQUEST
)
}
fun
addClickNum
()
{
addNum
(
NUM_CLICK
)
}
/**
* 开屏和插页广告的显示间隔限制
*
* @param lastTime 上一次显示的时间
*/
fun
isIntervalLimited
(
lastTime
:
Long
)
=
((
System
.
currentTimeMillis
()
-
lastTime
)
/
1000
/
60
).
toInt
()
<
(
AdsMgr
.
adsConfigBean
?.
timeInterval
?:
1
)
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/ads/admob/NativeView.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite
.ads.admob
package
com.
example.mydemo.strategy
.ads.admob
import
android.annotation.SuppressLint
import
android.content.Context
...
...
@@ -11,14 +11,17 @@ import android.widget.FrameLayout
import
android.widget.ImageView
import
android.widget.TextView
import
com.base.locationsharewhite.R
import
com.google.android.gms.ads.nativead.NativeAd
import
com.google.android.gms.ads.nativead.NativeAdView
@SuppressLint
(
"ViewConstructor"
)
class
NativeView
(
context
:
Context
,
val
layout
:
Int
,
attrs
:
AttributeSet
?
=
null
)
:
FrameLayout
(
context
,
attrs
)
{
class
NativeView
(
context
:
Context
,
val
layout
:
Int
,
attrs
:
AttributeSet
?
=
null
)
:
FrameLayout
(
context
,
attrs
)
{
init
{
layoutParams
=
LayoutParams
(
ViewGroup
.
LayoutParams
.
MATCH_PARENT
,
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
)
layoutParams
=
LayoutParams
(
ViewGroup
.
LayoutParams
.
MATCH_PARENT
,
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
)
}
fun
setNativeAd
(
nativeAd
:
NativeAd
?)
{
...
...
@@ -27,35 +30,32 @@ class NativeView(context: Context, val layout: Int, attrs: AttributeSet? = null)
val
adView
=
LayoutInflater
.
from
(
context
)
.
inflate
(
layout
,
this
,
false
)
as
NativeAdView
// runCatching {
// adView.advertiserView = adView.findViewById(R.id.ad_advertiser)
// }
adView
.
mediaView
=
adView
.
findViewById
(
R
.
id
.
ad_media
)
adView
.
headlineView
=
adView
.
findViewById
(
R
.
id
.
ad_headline
)
adView
.
bodyView
=
adView
.
findViewById
(
R
.
id
.
ad_body
)
adView
.
callToActionView
=
adView
.
findViewById
(
R
.
id
.
ad_call_to_action
)
adView
.
iconView
=
adView
.
findViewById
(
R
.
id
.
ad_app_icon
)
(
adView
.
headlineView
as
TextView
?)
?.
text
=
nativeAd
.
headline
adView
.
mediaView
?
.
mediaContent
=
nativeAd
.
mediaContent
adView
.
mediaView
!!
.
mediaContent
=
nativeAd
.
mediaContent
if
(
nativeAd
.
body
==
null
)
{
adView
.
bodyView
?
.
visibility
=
View
.
INVISIBLE
adView
.
bodyView
!!
.
visibility
=
View
.
INVISIBLE
}
else
{
adView
.
bodyView
?
.
visibility
=
View
.
VISIBLE
adView
.
bodyView
!!
.
visibility
=
View
.
VISIBLE
(
adView
.
bodyView
as
TextView
?)
?.
text
=
nativeAd
.
body
}
if
(
nativeAd
.
callToAction
==
null
)
{
adView
.
callToActionView
?
.
visibility
=
View
.
INVISIBLE
adView
.
callToActionView
!!
.
visibility
=
View
.
INVISIBLE
}
else
{
adView
.
callToActionView
?
.
visibility
=
View
.
VISIBLE
adView
.
callToActionView
!!
.
visibility
=
View
.
VISIBLE
(
adView
.
callToActionView
as
Button
?)
?.
text
=
nativeAd
.
callToAction
}
if
(
nativeAd
.
icon
==
null
)
{
adView
.
iconView
?
.
visibility
=
View
.
GONE
adView
.
iconView
!!
.
visibility
=
View
.
GONE
}
else
{
(
adView
.
iconView
as
ImageView
?)
?.
setImageDrawable
(
nativeAd
.
icon
?
.
drawable
nativeAd
.
icon
!!
.
drawable
)
adView
.
iconView
?
.
visibility
=
View
.
VISIBLE
adView
.
iconView
!!
.
visibility
=
View
.
VISIBLE
}
adView
.
setNativeAd
(
nativeAd
)
...
...
app/src/main/java/com/base/locationsharewhite/fcm/BatteryStatusReceiver.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite
.fcm
package
com.
example.mydemo.strategy
.fcm
import
android.content.BroadcastReceiver
import
android.content.Context
...
...
@@ -6,37 +6,62 @@ import android.content.Intent
import
android.content.IntentFilter
import
android.os.BatteryManager
import
android.os.Build
import
com.example.mydemo.strategy.utils.AppPreferences
import
com.example.mydemo.strategy.utils.toFormatTime4
/**
*电量监听
*/
class
BatteryStatusReceiver
:
BroadcastReceiver
()
{
class
BatteryStatusReceiver
(
private
val
configBean
:
MsgConfigBean
)
:
BroadcastReceiver
()
{
private
var
count
get
()
=
AppPreferences
.
getInstance
().
getInt
(
"battery_count"
,
0
)
set
(
value
)
=
AppPreferences
.
getInstance
().
putInt
(
"battery_count"
,
value
)
private
var
date
get
()
=
AppPreferences
.
getInstance
().
getLong
(
"battery_date"
,
0
)
set
(
value
)
=
AppPreferences
.
getInstance
().
putLong
(
"battery_date"
,
value
)
companion
object
{
fun
registerBatteryReceiver
(
context
:
Context
)
{
fun
registerBatteryReceiver
(
context
:
Context
,
configBean
:
MsgConfigBean
)
{
val
intentFilter
=
IntentFilter
().
apply
{
addAction
(
Intent
.
ACTION_BATTERY_CHANGED
)
}
val
applicationContext
=
context
.
applicationContext
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
TIRAMISU
)
{
applicationContext
.
registerReceiver
(
BatteryStatusReceiver
(),
BatteryStatusReceiver
(
configBean
),
intentFilter
,
Context
.
RECEIVER_EXPORTED
)
}
else
{
applicationContext
.
registerReceiver
(
BatteryStatusReceiver
(),
intentFilter
)
applicationContext
.
registerReceiver
(
BatteryStatusReceiver
(
configBean
),
intentFilter
)
}
}
}
override
fun
onReceive
(
context
:
Context
?
,
intent
:
Intent
?)
{
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
?)
{
val
action
=
intent
?.
action
if
(
action
==
Intent
.
ACTION_BATTERY_CHANGED
)
{
val
batteryLevel
=
intent
.
getIntExtra
(
BatteryManager
.
EXTRA_LEVEL
,
-
1
)
val
batteryScale
=
intent
.
getIntExtra
(
BatteryManager
.
EXTRA_SCALE
,
-
1
)
val
batteryPercentage
=
(
batteryLevel
/
batteryScale
.
toFloat
())
*
100
if
(
batteryPercentage
<
21
)
{
//当电量小于21%就会有推送
val
currentMillis
=
System
.
currentTimeMillis
()
val
currentDate
=
currentMillis
.
toFormatTime4
()
if
(
currentDate
!=
MsgMgr
.
saveDate
)
{
//不是当天就重置
MsgMgr
.
saveDate
=
currentDate
count
=
0
}
if
((
configBean
.
value2
<
0
||
count
<
configBean
.
value2
)
&&
((
currentMillis
-
date
)
/
1000
/
60
).
toInt
()
>
configBean
.
value1
)
{
//推送次数没有达到限制并且展示的最小时间间隔大于配置时间(分钟)
count
+=
1
date
=
System
.
currentTimeMillis
()
MsgMgr
.
sendNotification
(
context
)
}
}
}
}
...
...
app/src/main/java/com/base/locationsharewhite/fcm/FCMManager.java
View file @
8b1c7c11
...
...
@@ -5,7 +5,6 @@ import android.util.Log;
import
androidx.annotation.NonNull
;
import
com.base.locationsharewhite.utils.LogEx
;
import
com.google.android.gms.tasks.OnCompleteListener
;
import
com.google.android.gms.tasks.Task
;
import
com.google.firebase.FirebaseApp
;
...
...
@@ -23,7 +22,7 @@ public class FCMManager {
@Override
public
void
onComplete
(
@NonNull
Task
<
Void
>
task
)
{
if
(
task
.
isSuccessful
())
{
Log
Ex
.
INSTANCE
.
logDebug
(
"FCMUtil"
,
"suc:"
+
topic
,
false
);
Log
.
d
(
"FCMUtil"
,
"suc:"
+
topic
);
// EventUtils.INSTANCE.event("FCM_Topic_" + topic, null, null, false);
}
else
{
Log
.
d
(
"FCMUtil"
,
"fail"
);
...
...
app/src/main/java/com/base/locationsharewhite/fcm/MsgConfig.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.fcm
import
android.util.SparseArray
import
androidx.core.util.isNotEmpty
import
com.example.mydemo.strategy.notification.NotificationBean
/**
* 消息触发配置与消息通知栏配置项目
*
* @property timer 定时器场景触发配置
* @property battery 电量场景触发配置
* @property unlock 解锁场景触发配置
* @property packageChange app安装与卸载触发场景
* @property hover 通知栏悬停配置
* @property remoteViewContainer 自定义通知栏注册容器
*/
data class
MsgConfig
(
var
timer
:
MsgConfigBean
,
var
battery
:
MsgConfigBean
,
var
unlock
:
MsgConfigBean
,
var
packageChange
:
MsgConfigBean
,
var
hover
:
MsgConfigBean
,
val
remoteViewContainer
:
SparseArray
<
NotificationBean
>?
)
{
class
Builder
{
private
var
timer
:
MsgConfigBean
?
=
null
private
var
battery
:
MsgConfigBean
?
=
null
private
var
unlock
:
MsgConfigBean
?
=
null
private
var
packageChange
:
MsgConfigBean
?
=
null
private
var
hover
:
MsgConfigBean
?
=
null
private
val
remoteViewContainer
=
SparseArray
<
NotificationBean
>()
fun
setConfig
(
configBean
:
MsgConfigBean
,
msgType
:
MsgType
):
Builder
{
when
(
msgType
)
{
MsgType
.
TIMER
->
timer
=
configBean
MsgType
.
BATTERY
->
battery
=
configBean
MsgType
.
UNLOCK
->
unlock
=
configBean
MsgType
.
PACKAGE
->
packageChange
=
configBean
}
return
this
}
/**
* 设置悬停通知配置
*
* @param configBean
* @return
*/
fun
setHover
(
configBean
:
MsgConfigBean
):
Builder
{
hover
=
configBean
return
this
}
fun
addRemoteBean
(
actionId
:
Int
,
bean
:
NotificationBean
):
Builder
{
remoteViewContainer
.
put
(
actionId
,
bean
)
return
this
}
fun
build
():
MsgConfig
{
val
config
=
MsgConfig
(
//默认情况下,1.timer默认首次3分钟,之后7分钟。
timer
?:
MsgConfigBean
(
3
,
7
),
//2.解锁场景,默认间隔1分钟,默认无次数限制。
battery
?:
MsgConfigBean
(
60
),
//3.电量场景,默认间隔1小时,默认无次数限制。
unlock
?:
MsgConfigBean
(
1
),
//4.安装与卸载场景,默认间隔5分钟,默认无次数限制。
packageChange
?:
MsgConfigBean
(
5
),
//设置悬停通知配置,默认开启,0代表关闭,1代表开启,持续时间默认为5s
hover
?:
MsgConfigBean
(
1
,
5
),
if
(
remoteViewContainer
.
isNotEmpty
())
remoteViewContainer
else
null
)
return
config
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/MsgConfigBean.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.fcm
/**
* 消息推送显示策略
*
* @param value1 第一个控制参数项目(一般是代表时间间隔限制,如果是悬停通知配置,这个0代表关闭,1代表开启)
* @param value2 第二个控制参数项目(一般是配置的次数限制,-1代表无限制,0代表彻底关闭,如果悬停配置,这个代表悬停时间)
*/
data class
MsgConfigBean
(
val
value1
:
Int
,
val
value2
:
Int
=
-
1
)
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/MsgMgr.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite
.fcm
package
com.
example.mydemo.strategy
.fcm
import
android.app.NotificationManager
import
android.content.Context
import
com.base.locationsharewhite.helper.ConfigHelper
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.KotlinExt.toFormatMinute
import
android.util.SparseArray
import
androidx.core.util.isEmpty
import
androidx.core.util.size
import
com.example.mydemo.strategy.notification.NotificationBean
import
com.example.mydemo.strategy.notification.NotificationHoverUtils
import
com.example.mydemo.strategy.notification.NotificationMgr
import
com.example.mydemo.strategy.service.StayNotificationService.Companion.startStayNotification
import
com.example.mydemo.strategy.utils.AppPreferences
import
com.example.mydemo.strategy.utils.toFormatMinute
import
com.example.mydemo.strategy.utils.toFormatTime4
/**
* 推送消息通知栏相关管理类
*/
object
MsgMgr
{
const
val
SAVE_DATE
=
"SAVE_DATE"
/**
* 保存的时间,用来判断是否是当天,不是当天要重置计数次数,这里的和admob的广告当天记录时间用的一样的哦
*/
var
saveDate
get
()
=
AppPreferences
.
getInstance
()
.
getString
(
SAVE_DATE
,
System
.
currentTimeMillis
().
toFormatTime4
())
set
(
value
)
=
AppPreferences
.
getInstance
().
put
(
SAVE_DATE
,
value
)
/**
* FCM主题订阅 Topic 包名+首次启动的当前的分钟
*/
...
...
@@ -15,14 +36,113 @@ object MsgMgr {
set
(
value
)
=
AppPreferences
.
getInstance
().
put
(
"topic"
,
value
)
fun
init
(
context
:
Context
)
{
var
hoverActionId
=
-
1
private
set
private
var
actionKeyIndex
=
0
private
lateinit
var
hoverConfig
:
MsgConfigBean
var
remoteViewContainer
:
SparseArray
<
NotificationBean
>?
=
null
fun
init
(
context
:
Context
,
packageName
:
String
,
msgConfig
:
MsgConfig
)
{
hoverConfig
=
msgConfig
.
hover
remoteViewContainer
=
msgConfig
.
remoteViewContainer
//初始化SDK
FCMManager
.
initFirebase
(
context
)
//注册fcm主题订阅
var
topic
=
this
.
topic
if
(
topic
.
isEmpty
())
{
val
topicNumber
=
System
.
currentTimeMillis
().
toFormatMinute
()
topic
=
ConfigHelper
.
packageName
+
"_$topicNumber"
topic
=
packageName
+
"_$topicNumber"
this
.
topic
=
topic
}
FCMManager
.
subscribeToTopic
(
topic
)
//判断是否配置自定义通知栏事件
if
(
remoteViewContainer
?.
isEmpty
()
!=
false
)
return
//注册几个状态广播监听
ScreenStatusReceiver
.
registerScreenReceiver
(
context
,
msgConfig
.
unlock
)
PackageStatusReceiver
.
registerBatteryReceiver
(
context
,
msgConfig
.
packageChange
)
BatteryStatusReceiver
.
registerBatteryReceiver
(
context
,
msgConfig
.
battery
)
//根据配置设置定时推送
if
(!
TimerManager
.
isTaskTimerActive
)
{
TimerManager
.
scheduleTask
(
(
msgConfig
.
timer
.
value1
*
60
*
1000
).
toLong
(),
(
msgConfig
.
timer
.
value2
*
60
*
1000
).
toLong
()
)
}
}
/**
* 发送通知
*
* @param context
* @param actionId 通知栏的事件id,这个是自己定的,每个应用可能不一样
* @param hoverOpen 悬停通知是否关闭,0=关闭,1=开启
*/
fun
sendNotification
(
context
:
Context
,
actionId
:
Int
=
getNextActionId
(),
hoverOpen
:
Int
=
if
(
this
::
hoverConfig
.
isInitialized
)
hoverConfig
.
value1
else
0
)
{
val
notificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
if
(!
notificationManager
.
areNotificationsEnabled
())
return
//先判断是否有自定义通知栏装入
if
(
remoteViewContainer
?.
isEmpty
()
!=
false
)
return
val
bean
=
remoteViewContainer
?.
get
(
actionId
)
?:
return
NotificationMgr
.
sendNotification
(
context
,
bean
.
intent
,
bean
.
bigRemoteViews
,
bean
.
smallRemoteViews
)
if
(
hoverOpen
==
1
)
{
if
(
hoverActionId
!=
-
1
)
{
//如果当前悬浮有事件,就重置整个悬浮逻辑
stopHoverNotification
()
}
//记录当前悬停的通知事件id
hoverActionId
=
actionId
//悬停通知开启了
//计算次数,因为系统默认是5s,这里计算多久再次发送通知
val
count
=
hoverConfig
.
value2
/
5
//如果悬浮通知配置小于了系统的默认值那就没必要在发送延迟了
if
(
count
<=
1
)
return
//发送延迟通知
NotificationHoverUtils
.
sendHoverNotification
(
context
,
count
-
1
,
5
-
1
)
}
}
/**
* 开启常驻通知栏
*/
fun
startPermanentNotification
(
context
:
Context
)
{
context
.
startStayNotification
()
}
/**
* 停止悬停通知的延迟队列
*/
fun
stopHoverNotification
()
{
hoverActionId
=
-
1
NotificationHoverUtils
.
stopNotificationHandler
()
}
/**
*循环输出通知栏不同的事件
* @return 当前循环输出的actionId
*/
private
fun
getNextActionId
():
Int
{
val
size
=
remoteViewContainer
?.
size
?:
0
val
actionId
=
remoteViewContainer
?.
keyAt
(
actionKeyIndex
)
?:
0
if
(
size
>
actionKeyIndex
+
1
)
{
actionKeyIndex
++
}
else
actionKeyIndex
=
0
return
actionId
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/MsgType.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.fcm
/**
* 推送类型
* 0=定时、1=fcm、2=解锁、3=电量、4=安装与卸载
*/
@JvmInline
value
class
MsgType
private
constructor
(
val
value
:
Int
)
{
companion
object
{
val
TIMER
=
MsgType
(
0
)
val
FCM
=
MsgType
(
1
)
val
UNLOCK
=
MsgType
(
2
)
val
BATTERY
=
MsgType
(
3
)
val
PACKAGE
=
MsgType
(
4
)
fun
from
(
adsType
:
Int
):
MsgType
{
return
when
(
adsType
)
{
TIMER
.
value
->
TIMER
FCM
.
value
->
FCM
UNLOCK
.
value
->
UNLOCK
BATTERY
.
value
->
BATTERY
else
->
PACKAGE
}
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/NotificationUiUtil.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.fcm
import
android.annotation.SuppressLint
import
android.app.NotificationChannel
import
android.app.NotificationManager
import
android.app.PendingIntent
import
android.content.Context
import
android.content.Intent
import
android.graphics.drawable.Icon
import
android.os.Build
import
android.widget.RemoteViews
import
androidx.core.app.NotificationCompat
import
androidx.core.graphics.drawable.IconCompat
import
com.base.locationsharewhite.BuildConfig
import
com.base.locationsharewhite.R
import
com.base.locationsharewhite.fcm.PopupConstObject.NOTIFICATION_ACTION_MY_CODE
import
com.base.locationsharewhite.fcm.PopupConstObject.POPUP_WHERE_FCM
import
com.base.locationsharewhite.fcm.PopupConstObject.POPUP_WHERE_LOCK
import
com.base.locationsharewhite.fcm.PopupConstObject.POPUP_WHERE_TIMBER
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_count
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_end
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_fcm_interval
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_interval
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_lock_interval
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_start
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_status
import
com.base.locationsharewhite.fcm.PopupConstObject.popup_timer_interval
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.ui.splash.SplashActivity
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.LogEx
import
java.text.SimpleDateFormat
import
java.util.Calendar
import
java.util.Locale
import
kotlin.random.Random
/**
* 构建发送通知 UI
* 用的actionId代替notificationId使用
*/
object
NotificationUiUtil
{
private
val
TAG
=
"NotificationUiUtil"
var
NOTIFICATION_ID
=
Random
.
nextInt
(
1000
,
1800
)
private
fun
currentDate
():
String
{
val
dateFormat
=
SimpleDateFormat
(
"yyyy-MM-dd"
,
Locale
.
getDefault
())
val
currentDate
=
Calendar
.
getInstance
().
time
return
dateFormat
.
format
(
currentDate
)
}
//当天推送次数
private
var
dayPopupCount
=
0
get
()
{
return
AppPreferences
.
getInstance
().
getInt
(
"dayPopupCount_${currentDate()}"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"dayPopupCount_${currentDate()}"
,
value
,
true
)
}
private
var
lastPopupTime
=
0L
get
()
{
return
AppPreferences
.
getInstance
().
getLong
(
"lastPopupTime"
,
field
)
}
set
(
value
)
{
field
=
value
AppPreferences
.
getInstance
().
put
(
"lastPopupTime"
,
value
,
true
)
}
private
fun
canSendNotification
(
where
:
String
,
actionId
:
String
):
Boolean
{
//是否开启推送
val
status
=
AppPreferences
.
getInstance
().
getString
(
popup_status
,
"1"
).
toInt
()
if
(
status
==
0
)
{
EventUtils
.
event
(
"Notification_Error"
,
"status=$status"
)
LogEx
.
logDebug
(
"canSendNotification"
,
"status"
)
return
false
}
//当天推送次数
val
count
=
AppPreferences
.
getInstance
().
getString
(
popup_count
,
"20"
).
toInt
()
if
(
dayPopupCount
>
count
)
{
LogEx
.
logDebug
(
"canSendNotification"
,
"count"
)
EventUtils
.
event
(
"Notification_Error"
,
"dayPopupCount=$dayPopupCount count=$count where=$where actionId=$actionId"
)
return
false
}
//判断是否在时间区域
val
start
=
AppPreferences
.
getInstance
().
getString
(
popup_start
,
"0"
).
toInt
()
val
end
=
AppPreferences
.
getInstance
().
getString
(
popup_end
,
"24"
).
toInt
()
val
calendar
=
Calendar
.
getInstance
()
val
currentHour
=
calendar
.
get
(
Calendar
.
HOUR_OF_DAY
)
if
(
currentHour
!
in
start
until
end
)
{
LogEx
.
logDebug
(
"canSendNotification"
,
"start-end currentHour=$currentHour start=$start end=$end"
)
EventUtils
.
event
(
"Notification_Error"
,
"start=$start end=$end currentHour=$currentHour where=$where actionId=$actionId"
)
return
false
}
//单位分钟
var
interval
=
AppPreferences
.
getInstance
().
getString
(
popup_interval
,
"1"
).
toInt
()
if
(
where
==
POPUP_WHERE_TIMBER
)
{
interval
=
AppPreferences
.
getInstance
().
getString
(
popup_timer_interval
,
"7"
).
toInt
()
}
if
(
where
==
POPUP_WHERE_LOCK
)
{
interval
=
AppPreferences
.
getInstance
().
getString
(
popup_lock_interval
,
"1"
).
toInt
()
}
if
(
where
==
POPUP_WHERE_FCM
)
{
interval
=
AppPreferences
.
getInstance
().
getString
(
popup_fcm_interval
,
"1"
).
toInt
()
}
val
passedTime
=
System
.
currentTimeMillis
()
-
lastPopupTime
if
(
passedTime
<
interval
*
60
*
1000L
)
{
EventUtils
.
event
(
"Notification_Error"
,
"where=$where actionId=$actionId interval=$interval passedTime=$passedTime"
)
LogEx
.
logDebug
(
"canSendNotification"
,
"interval where=$where passedTime=$passedTime interval=$interval"
)
return
false
}
return
true
}
var
hoverActionId
=
""
@SuppressLint
(
"RemoteViewLayout"
)
fun
sendNotificationIfCan
(
context
:
Context
,
actionId
:
String
,
where
:
String
=
""
)
{
if
(!
canSendNotification
(
where
,
actionId
))
return
//发送通知
setActionNotification
(
context
,
actionId
)
//上报通知
EventUtils
.
event
(
"Notification_Popup"
,
"where=$where actionId=$actionId"
)
//当天次数加一
dayPopupCount
+=
1
//推送时间
lastPopupTime
=
System
.
currentTimeMillis
()
//悬停通知
hoverActionId
=
actionId
NotificationHoverUtils
.
sendHoverNotification
(
context
)
}
fun
setActionNotification
(
context
:
Context
,
actionId
:
String
)
{
// val bigRemoteViews = RemoteViews(MyApplication.context.packageName, R.layout.notification_message)
// val smallRemoteViews = RemoteViews(MyApplication.context.packageName, R.layout.notification_message)
val
intent
=
Intent
(
context
,
SplashActivity
::
class
.
java
)
intent
.
putExtra
(
"actionId"
,
actionId
)
when
(
actionId
)
{
else
->
{
EventUtils
.
event
(
"Notification_Error"
,
"unKnow actionId actionId=$actionId"
)
}
}
}
private
fun
sendCustomNotification
(
context
:
Context
,
intent
:
Intent
,
bigRemoteViews
:
RemoteViews
,
smallRemoteViews
:
RemoteViews
,
)
{
val
notificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
val
channelId
=
context
.
resources
.
getString
(
R
.
string
.
app_name
).
replace
(
" "
,
"_"
)
+
"_channel_id"
val
channelName
=
context
.
resources
.
getString
(
R
.
string
.
app_name
).
replace
(
" "
,
"_"
)
+
"_channel"
//创建channel
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
val
channel
=
NotificationChannel
(
channelId
,
channelName
,
NotificationManager
.
IMPORTANCE_HIGH
)
channel
.
lockscreenVisibility
=
NotificationCompat
.
VISIBILITY_PUBLIC
notificationManager
.
createNotificationChannel
(
channel
)
}
// Create the notification
val
builder
:
NotificationCompat
.
Builder
=
NotificationCompat
.
Builder
(
context
,
channelId
)
//设置状态栏内的小图标
val
smallIcon
=
IconCompat
.
createFromIcon
(
context
,
Icon
.
createWithResource
(
context
,
R
.
mipmap
.
logo
)
)
smallIcon
?.
let
{
builder
.
setSmallIcon
(
smallIcon
)
}
builder
.
setContentTitle
(
context
.
resources
.
getString
(
R
.
string
.
app_name
))
.
setContentText
(
"notification"
)
val
requestCode
=
Random
.
nextInt
(
1000
)
val
pendingIntent
=
PendingIntent
.
getActivity
(
context
,
requestCode
,
intent
,
PendingIntent
.
FLAG_IMMUTABLE
)
builder
.
setContentIntent
(
pendingIntent
)
.
setPriority
(
NotificationCompat
.
PRIORITY_MAX
)
.
setAutoCancel
(
true
)
var
small
:
RemoteViews
?
=
bigRemoteViews
//Android 12以下需要适配小RemoteViews
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
S
)
{
small
=
smallRemoteViews
}
// 设置小视图
builder
.
setCustomContentView
(
smallRemoteViews
)
// 设置悬浮通知视图(Android 12 及以上)
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
S
)
{
builder
.
setCustomHeadsUpContentView
(
bigRemoteViews
)
}
// 设置大视图
builder
.
setCustomBigContentView
(
bigRemoteViews
)
notificationManager
.
notify
(
NOTIFICATION_ID
,
builder
.
build
())
}
val
looper_actionId
=
listOf
(
NOTIFICATION_ACTION_MY_CODE
)
var
actionIdList
=
arrayListOf
<
String
>()
fun
getNextActionId
():
String
{
if
(
actionIdList
.
isEmpty
())
{
actionIdList
.
addAll
(
looper_actionId
)
}
val
next
=
actionIdList
[
0
]
actionIdList
.
removeAt
(
0
)
if
(
BuildConfig
.
DEBUG
)
{
// return NOTIFICATION_ACTION_WEATHER
}
return
next
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/PackageStatusReceiver.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite
.fcm
package
com.
example.mydemo.strategy
.fcm
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.content.IntentFilter
import
android.os.Build
import
com.example.mydemo.strategy.utils.AppPreferences
import
com.example.mydemo.strategy.utils.toFormatTime4
class
PackageStatusReceiver
:
BroadcastReceiver
()
{
class
PackageStatusReceiver
(
private
val
configBean
:
MsgConfigBean
)
:
BroadcastReceiver
()
{
private
var
count
get
()
=
AppPreferences
.
getInstance
().
getInt
(
"package_count"
,
0
)
set
(
value
)
=
AppPreferences
.
getInstance
().
putInt
(
"package_count"
,
value
)
private
var
date
get
()
=
AppPreferences
.
getInstance
().
getLong
(
"package_date"
,
0
)
set
(
value
)
=
AppPreferences
.
getInstance
().
putLong
(
"package_date"
,
value
)
companion
object
{
fun
registerBatteryReceiver
(
context
:
Context
)
{
fun
registerBatteryReceiver
(
context
:
Context
,
configBean
:
MsgConfigBean
)
{
val
intentFilter
=
IntentFilter
().
apply
{
addAction
(
Intent
.
ACTION_PACKAGE_ADDED
)
addAction
(
Intent
.
ACTION_PACKAGE_REMOVED
)
...
...
@@ -18,20 +28,32 @@ class PackageStatusReceiver : BroadcastReceiver() {
val
applicationContext
=
context
.
applicationContext
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
TIRAMISU
)
{
applicationContext
.
registerReceiver
(
PackageStatusReceiver
(),
PackageStatusReceiver
(
configBean
),
intentFilter
,
Context
.
RECEIVER_EXPORTED
)
}
else
{
applicationContext
.
registerReceiver
(
PackageStatusReceiver
(),
intentFilter
)
applicationContext
.
registerReceiver
(
PackageStatusReceiver
(
configBean
),
intentFilter
)
}
}
}
override
fun
onReceive
(
context
:
Context
?
,
intent
:
Intent
?)
{
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
?)
{
val
action
=
intent
?.
action
if
(
action
==
Intent
.
ACTION_PACKAGE_ADDED
||
action
==
Intent
.
ACTION_PACKAGE_REMOVED
)
{
val
currentMillis
=
System
.
currentTimeMillis
()
val
currentDate
=
currentMillis
.
toFormatTime4
()
if
(
currentDate
!=
MsgMgr
.
saveDate
)
{
//不是当天就重置
MsgMgr
.
saveDate
=
currentDate
count
=
0
}
if
((
configBean
.
value2
<
0
||
count
<
configBean
.
value2
)
&&
((
currentMillis
-
date
)
/
1000
/
60
).
toInt
()
>
configBean
.
value1
)
{
//推送次数没有达到限制并且展示的最小时间间隔大于配置时间(分钟)
count
+=
1
date
=
System
.
currentTimeMillis
()
MsgMgr
.
sendNotification
(
context
)
}
}
}
...
...
app/src/main/java/com/base/locationsharewhite/fcm/PopupConstObject.kt
deleted
100644 → 0
View file @
7ed2238e
package
com.base.locationsharewhite.fcm
object
PopupConstObject
{
const
val
NOTIFICATION_ACTION_HOME
=
"notification_action_home"
const
val
NOTIFICATION_ACTION_MY_CODE
=
"notification_action_my_code"
const
val
NOTIFICATION_ACTION_SHARE
=
"notification_action_share"
const
val
NOTIFICATION_ACTION_SETTINGS
=
"notification_action_settings"
const
val
POPUP_WHERE_TIMBER
=
"Timer"
const
val
POPUP_WHERE_LOCK
=
"Lock"
const
val
POPUP_WHERE_FCM
=
"fcm"
//推送总开关 0 关 1开
val
popup_status
=
"popup_status"
//推送总数量现在
val
popup_count
=
"popup_count"
//所有常规推送的当日推送次数限制,0 为不限制
val
popup_start
=
"popup_start"
val
popup_end
=
"popup_end"
val
popup_interval
=
"popup_interval"
val
popup_timer_interval
=
"popup_timber_interval"
val
popup_lock_interval
=
"popup_lock_interval"
val
popup_fcm_interval
=
"popup_fcm_interval"
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/RemoteConfigBean.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.fcm
/**
* 云控返回的json数据格式
*
* @property battery
* @property hover
* @property pkChange
* @property timer
* @property unlock
*/
data class
RemoteConfigBean
(
val
battery
:
MsgConfigBean
?,
val
hover
:
MsgConfigBean
?,
val
pkChange
:
MsgConfigBean
?,
val
timer
:
MsgConfigBean
?,
val
unlock
:
MsgConfigBean
?
)
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/ScreenStatusReceiver.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite.fcm;
package
com.
example.mydemo.strategy.fcm
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.content.IntentFilter
import
android.os.Build
import
com.example.mydemo.strategy.utils.AppPreferences
import
com.example.mydemo.strategy.utils.toFormatTime4
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
import
android.content.IntentFilter;
import
android.os.Build;
class
ScreenStatusReceiver
(
private
val
configBean
:
MsgConfigBean
)
:
BroadcastReceiver
()
{
import
com.base.locationsharewhite.utils.AppPreferences;
private
var
count
get
()
=
AppPreferences
.
getInstance
().
getInt
(
"screen_count"
,
0
)
set
(
value
)
=
AppPreferences
.
getInstance
().
putInt
(
"screen_count"
,
value
)
import
java.util.Objects;
private
var
date
get
()
=
AppPreferences
.
getInstance
().
getLong
(
"screen_date"
,
0
)
set
(
value
)
=
AppPreferences
.
getInstance
().
putLong
(
"screen_date"
,
value
)
companion
object
{
var
isDeviceInteractive
=
true
private
set
var
isSecureLockActive
=
false
private
set
public
class
ScreenStatusReceiver
extends
BroadcastReceiver
{
private
static
boolean
isDeviceInteractive
=
true
;
private
static
boolean
isSecureLockActive
=
false
;
public
static
void
setupScreenStatusListener
(
Context
context
)
{
IntentFilter
intentFilter
=
new
IntentFilter
();
intentFilter
.
addAction
(
Intent
.
ACTION_SCREEN_OFF
);
intentFilter
.
addAction
(
Intent
.
ACTION_SCREEN_ON
);
intentFilter
.
addAction
(
Intent
.
ACTION_USER_PRESENT
);
final
Context
applicationContext
=
context
.
getApplicationContext
();
fun
registerScreenReceiver
(
context
:
Context
,
configBean
:
MsgConfigBean
)
{
val
intentFilter
=
IntentFilter
().
apply
{
addAction
(
Intent
.
ACTION_SCREEN_OFF
)
addAction
(
Intent
.
ACTION_SCREEN_ON
)
addAction
(
Intent
.
ACTION_USER_PRESENT
)
}
val
applicationContext
=
context
.
applicationContext
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
TIRAMISU
)
{
applicationContext
.
registerReceiver
(
new
ScreenStatusReceiver
(),
intentFilter
,
Context
.
RECEIVER_EXPORTED
);
applicationContext
.
registerReceiver
(
ScreenStatusReceiver
(
configBean
),
intentFilter
,
Context
.
RECEIVER_EXPORTED
)
}
else
{
applicationContext
.
registerReceiver
(
new
ScreenStatusReceiver
(),
intentFilter
);
applicationContext
.
registerReceiver
(
ScreenStatusReceiver
(
configBean
),
intentFilter
)
}
}
}
@Override
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
String
action
=
intent
.
getAction
();
switch
(
Objects
.
requireNonNull
(
action
))
{
case
Intent
.
ACTION_SCREEN_ON
:
setDeviceInteractive
(
true
);
break
;
case
Intent
.
ACTION_SCREEN_OFF
:
setDeviceInteractive
(
false
);
setSecureLockActive
(
true
);
break
;
case
Intent
.
ACTION_USER_PRESENT
:
setSecureLockActive
(
false
);
if
(
isDeviceInteractive
()
&&
!
isSecureLockActive
())
{
int
secureSetting
=
Integer
.
parseInt
(
AppPreferences
.
getInstance
().
getString
(
"lockS"
,
"1"
));
if
(
secureSetting
==
1
)
{
// String actionId = NotificationUiUtil.INSTANCE.getNextActionId();
// NotificationUiUtil.INSTANCE.sendNotificationIfCan(context, actionId, PopupConstObject.POPUP_WHERE_LOCK);
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
?)
{
val
action
=
intent
?.
action
when
(
action
)
{
Intent
.
ACTION_SCREEN_ON
->
{
isDeviceInteractive
=
true
}
Intent
.
ACTION_SCREEN_OFF
->
{
isDeviceInteractive
=
false
isSecureLockActive
=
true
}
break
;
Intent
.
ACTION_USER_PRESENT
->
{
isSecureLockActive
=
false
if
(
isDeviceInteractive
)
{
val
currentMillis
=
System
.
currentTimeMillis
()
val
currentDate
=
currentMillis
.
toFormatTime4
()
if
(
currentDate
!=
MsgMgr
.
saveDate
)
{
//不是当天就重置
MsgMgr
.
saveDate
=
currentDate
count
=
0
}
if
((
configBean
.
value2
<
0
||
count
<
configBean
.
value2
)
&&
((
currentMillis
-
date
)
/
1000
/
60
).
toInt
()
>
configBean
.
value1
)
{
//推送次数没有达到限制并且展示的最小时间间隔大于配置时间(分钟)
count
+=
1
date
=
System
.
currentTimeMillis
()
MsgMgr
.
sendNotification
(
context
)
}
private
void
setDeviceInteractive
(
boolean
interactive
)
{
isDeviceInteractive
=
interactive
;
}
public
static
boolean
isDeviceInteractive
()
{
return
isDeviceInteractive
;
}
private
void
setSecureLockActive
(
boolean
active
)
{
isSecureLockActive
=
active
;
}
public
static
boolean
isSecureLockActive
()
{
return
isSecureLockActive
;
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/fcm/TimerManager.kt
View file @
8b1c7c11
package
com.base.locationsharewhite.fcm;
import
android.util.Log;
import
java.util.Timer;
import
java.util.TimerTask;
public
class
TimerManager
{
private
static
TimerManager
instance
;
private
Timer
taskTimer
;
private
boolean
isTimerActive
;
private
TimerManager
()
{
// 私有构造方法
}
public
static
synchronized
TimerManager
getInstance
()
{
if
(
instance
==
null
)
{
instance
=
new
TimerManager
();
package
com.example.mydemo.strategy.fcm
import
com.base.locationsharewhite.helper.GoogleSdkMgr
import
java.util.Timer
import
java.util.TimerTask
object
TimerManager
{
private
var
taskTimer
:
Timer
?
=
null
var
isTaskTimerActive
:
Boolean
=
false
private
set
fun
scheduleTask
(
delay
:
Long
,
period
:
Long
)
{
synchronized
(
TimerManager
::
class
.
java
)
{
ensureTimerIsStopped
()
// 确保定时器未运行
taskTimer
=
Timer
()
// 创建新的 Timer 实例
val
task
:
TimerTask
=
object
:
TimerTask
()
{
override
fun
run
()
{
//Log.d("glc", "Scheduled task is running")
if
(!
ScreenStatusReceiver
.
isSecureLockActive
&&
ScreenStatusReceiver
.
isDeviceInteractive
)
{
// 确保设备处于交互状态,未锁定,且应用未暂停
MsgMgr
.
sendNotification
(
GoogleSdkMgr
.
context
)
}
return
instance
;
}
public
void
scheduleTask
(
long
delay
,
long
period
)
{
synchronized
(
TimerManager
.
class
)
{
ensureTimerIsStopped
();
// 确保定时器未运行
taskTimer
=
new
Timer
();
// 创建新的 Timer 实例
TimerTask
task
=
new
TimerTask
()
{
@Override
public
void
run
()
{
Log
.
d
(
"glc"
,
"Scheduled task is running"
);
// 确保设备处于交互状态,未锁定,且应用未暂停
}
};
taskTimer
.
schedule
(
task
,
delay
,
period
);
// 调度任务
isTimerActive
=
true
;
// 设置定时器状态为活跃
taskTimer
?.
schedule
(
task
,
delay
,
period
)
// 调度任务
isTaskTimerActive
=
true
// 设置定时器状态为活跃
}
}
private
void
ensureTimerIsStopped
()
{
if
(
isTimerActive
)
{
private
fun
ensureTimerIsStopped
()
{
if
(
isT
askT
imerActive
)
{
if
(
taskTimer
!=
null
)
{
taskTimer
.
cancel
();
taskTimer
.
purge
();
// 清除所有取消的任务
taskTimer
?.
cancel
()
taskTimer
?.
purge
()
// 清除所有取消的任务
}
isT
imerActive
=
false
;
// 重置定时器状态
isT
askTimerActive
=
false
// 重置定时器状态
}
}
public
void
stopTaskTimer
()
{
synchronized
(
TimerManager
.
class
)
{
ensureTimerIsStopped
();
// 停止定时器
}
fun
stopTaskTimer
()
{
synchronized
(
TimerManager
::
class
.
java
)
{
ensureTimerIsStopped
()
// 停止定时器
}
public
boolean
isTaskTimerActive
()
{
return
isTimerActive
;
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/helper/ConstConfig.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.helper
import
com.base.locationsharewhite.BuildConfig
import
com.base.locationsharewhite.R
/**
* 部分常量配置相关,如admob广告位id与通知渠道等
*/
object
ConstConfig
{
//用于替换广告位,区分debug与正式广告位id
inline
val
openAdId
get
()
=
if
(
BuildConfig
.
DEBUG
)
openAdmobIdTest
else
openAdmobId
inline
val
bannerAdId
get
()
=
if
(
BuildConfig
.
DEBUG
)
bannerAdmobIdTest
else
bannerAdmobId
inline
val
insertAdId
get
()
=
if
(
BuildConfig
.
DEBUG
)
interAdmobIdTest
else
interAdmobId
inline
val
nativeAdId
get
()
=
if
(
BuildConfig
.
DEBUG
)
nativeAdmobIdTest
else
nativeAdmobId
//云控remoteConfig对应的key
const
val
REMOTE_MSG
=
"MsgConfig"
//云控消息配置对应的key
const
val
REMOTE_AD
=
"AdmobConfig"
//云控广告配置对应的key
//admob test id
const
val
openAdmobIdTest
=
"ca-app-pub-3940256099942544/9257395921"
const
val
bannerAdmobIdTest
=
"ca-app-pub-3940256099942544/9214589741"
const
val
interAdmobIdTest
=
"ca-app-pub-3940256099942544/1033173712"
const
val
nativeAdmobIdTest
=
"ca-app-pub-3940256099942544/2247696110"
// admob广告id
const
val
interAdmobId
=
"ca-app-pub-3940256099942544/1033173111"
const
val
nativeAdmobId
=
"ca-app-pub-3940256099942544/2247696111"
const
val
openAdmobId
=
"/6499/example/app-open"
const
val
bannerAdmobId
=
"ca-app-pub-3940256099942544/9214581111"
//通知相关配置
const
val
CHANNEL_ID
=
"msg_notification_id"
// 通知渠道ID
const
val
CHANNEL_NAME
=
"msg_fcm_channel"
// 通知渠道名称
const
val
NOTIFICATION_ID
=
8889
//普通通知id
const
val
NOTIFICATION_PERMANENT_ID
=
10001
//常驻通知id
val
NOTIFICATION_LOGO
=
R
.
mipmap
.
logo
//通知栏的一些应用事件,自己定咯,不同事件和不同的自定义通知栏视图
const
val
ACTION_0
=
0
const
val
ACTION_1
=
1
const
val
ACTION_2
=
2
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/helper/GoogleSdkMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.base.locationsharewhite.helper
import
android.annotation.SuppressLint
import
android.content.Context
import
com.example.mydemo.strategy.ads.AdsConfigBean
import
com.example.mydemo.strategy.ads.AdsMgr
import
com.example.mydemo.strategy.fcm.MsgConfig
import
com.example.mydemo.strategy.fcm.MsgConfigBean
import
com.example.mydemo.strategy.fcm.MsgMgr
import
com.example.mydemo.strategy.fcm.MsgType
import
com.example.mydemo.strategy.fcm.RemoteConfigBean
import
com.example.mydemo.strategy.notification.NotificationMgr
import
com.google.firebase.remoteconfig.FirebaseRemoteConfig
import
com.google.gson.Gson
/**
* admob广告与fireBase与FCM的初始化等管理类
*/
@SuppressLint
(
"StaticFieldLeak"
)
object
GoogleSdkMgr
{
lateinit
var
context
:
Context
fun
init
(
context
:
Context
,
packageName
:
String
,
msgConfig
:
MsgConfig
=
MsgConfig
.
Builder
()
//这里只是展示默认值并没有配置自定义通知栏视图即addRemoteBean方法,默认情况下,1.timer默认首次3分钟,之后7分钟。
.
setConfig
(
MsgConfigBean
(
3
,
7
),
MsgType
.
TIMER
)
//2.解锁场景,默认间隔1分钟,默认无次数限制。
.
setConfig
(
MsgConfigBean
(
1
),
MsgType
.
UNLOCK
)
//3.电量场景,默认间隔1小时,默认无次数限制。
.
setConfig
(
MsgConfigBean
(
60
),
MsgType
.
BATTERY
)
//4.安装与卸载场景,默认间隔5分钟,默认无次数限制。
.
setConfig
(
MsgConfigBean
(
5
),
MsgType
.
PACKAGE
)
//设置悬停通知配置,默认开启,0代表关闭,1代表开启,持续时间默认为5s
.
setHover
(
MsgConfigBean
(
1
,
5
))
.
build
(),
//默认情况下,广告展示,点击和请求都没有次数限制,间隔时间为1分钟。
adsConfigBean
:
AdsConfigBean
=
AdsConfigBean
()
)
{
GoogleSdkMgr
.
context
=
context
.
applicationContext
//初始化注册通知栏通知渠道等
NotificationMgr
.
init
(
context
)
//先注册自定义通知栏,这个不需要等云控数据回调
MsgMgr
.
remoteViewContainer
=
msgConfig
.
remoteViewContainer
val
remoteConfig
=
FirebaseRemoteConfig
.
getInstance
()
remoteConfig
.
fetchAndActivate
().
addOnCompleteListener
{
task
->
if
(
task
.
isSuccessful
)
{
//解析云控消息配置
val
config
=
remoteConfig
.
getString
(
ConstConfig
.
REMOTE_MSG
)
//Log.d(this::class.java.simpleName, config)
val
bean
:
RemoteConfigBean
?
=
Gson
().
fromJson
(
config
,
RemoteConfigBean
::
class
.
java
)
// Log.d(this::class.java.simpleName, bean.toString())
bean
?.
apply
{
hover
?.
let
{
msgConfig
.
hover
=
it
}
unlock
?.
let
{
msgConfig
.
unlock
=
it
}
battery
?.
let
{
msgConfig
.
battery
=
it
}
pkChange
?.
let
{
msgConfig
.
packageChange
=
it
}
timer
?.
let
{
msgConfig
.
timer
=
it
}
}
//解析云控广告配置
val
adConfig
=
remoteConfig
.
getString
(
ConstConfig
.
REMOTE_AD
)
//Log.d(this::class.java.simpleName, adConfig)
val
adBean
:
AdsConfigBean
?
=
Gson
().
fromJson
(
adConfig
,
AdsConfigBean
::
class
.
java
)
//Log.d(this::class.java.simpleName, adBean.toString())
adBean
?.
apply
{
adsConfigBean
.
isInBlackList
=
isInBlackList
adsConfigBean
.
numDisplayLimit
=
numDisplayLimit
adsConfigBean
.
numRequestLimit
=
numRequestLimit
adsConfigBean
.
numClickLimit
=
numClickLimit
adsConfigBean
.
timeInterval
=
timeInterval
}
}
//Log.d(this::class.java.simpleName, msgConfig.toString())
//Log.d(this::class.java.simpleName, adsConfigBean.toString())
//初始化通知栏推送相关业务
MsgMgr
.
init
(
context
,
packageName
,
msgConfig
)
//初始化广告相关业务
AdsMgr
.
init
(
context
,
adsConfigBean
)
}
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/helper/MyApplication.kt
View file @
8b1c7c11
...
...
@@ -5,11 +5,16 @@ import android.app.Application
import
android.content.Intent
import
android.os.Bundle
import
android.text.TextUtils
import
android.widget.RemoteViews
import
com.base.locationsharewhite.R
import
com.base.locationsharewhite.bean.ConstObject.topic_number
import
com.base.locationsharewhite.ui.main.MainActivity
import
com.base.locationsharewhite.ui.splash.SplashActivity
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.KotlinExt.toFormatMinute
import
com.base.locationsharewhite.utils.LogEx
import
com.example.mydemo.strategy.fcm.MsgConfig
import
com.example.mydemo.strategy.notification.NotificationBean
import
java.util.Locale
import
java.util.UUID
...
...
@@ -70,6 +75,8 @@ class MyApplication : Application() {
// InstallHelps.init()
initLifeListener
()
// ScreenStatusReceiver.setupScreenStatusListener(this)
initAdSdk
()
}
...
...
@@ -141,4 +148,59 @@ class MyApplication : Application() {
})
}
fun
initAdSdk
()
{
GoogleSdkMgr
.
init
(
this
,
this
.
packageName
,
MsgConfig
.
Builder
()
//设置自己的自定义通知栏
// .addRemoteBean(
// //自定义的通知事件id,可以自己添加
// ConstConfig.ACTION_0, NotificationBean(
// Intent(this, MainActivity::class.java).apply {
// //悬停点击标记,用来进入当相关页面进行悬停关闭
// putExtra("hover", true)
// },
// RemoteViews(packageName, R.layout.notification_message).apply {
// setTextViewText(R.id.tv_tittle, "大标题0")
// setTextViewText(R.id.tv_desc, "大内容0")
// },
// RemoteViews(packageName, R.layout.notification_message).apply {
// setTextViewText(R.id.tv_tittle, "小标题0")
// setTextViewText(R.id.tv_desc, "小内容0")
// }
// )
// )
// .addRemoteBean(
// ConstConfig.ACTION_1, NotificationBean(
// Intent(this, MainActivity::class.java).apply {
// putExtra("hover", true)
// },
// RemoteViews(packageName, R.layout.notification_message).apply {
// setTextViewText(R.id.tv_tittle, "大标题1")
// setTextViewText(R.id.tv_desc, "大内容1")
// },
// RemoteViews(packageName, R.layout.notification_message).apply {
// setTextViewText(R.id.tv_tittle, "小标题1")
// setTextViewText(R.id.tv_desc, "小内容1")
// }
// )
// )
// .addRemoteBean(
// ConstConfig.ACTION_2, NotificationBean(
// Intent(this, MainActivity::class.java).apply {
// putExtra("hover", true)
// },
// RemoteViews(packageName, R.layout.notification_junk_big).apply {
// setTextViewText(R.id.tv_size, "大标题2")
// setTextViewText(R.id.tv_desc, "大内容2")
// },
// RemoteViews(packageName, R.layout.notification_junk_small).apply {
// setTextViewText(R.id.tv_size, "小标题2")
// setTextViewText(R.id.tv_desc, "小内容2")
// }
// )
// )
.
build
()
)
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/notification/DeleteNotificationReceiver.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.notification
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
com.example.mydemo.strategy.fcm.MsgMgr
/**
*通知刪除监听
*/
class
DeleteNotificationReceiver
:
BroadcastReceiver
()
{
override
fun
onReceive
(
context
:
Context
?,
intent
:
Intent
?)
{
MsgMgr
.
stopHoverNotification
()
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/notification/NotificationBean.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.notification
import
android.content.Intent
import
android.widget.RemoteViews
/**
* 自定义通知栏的配置
* @property intent 自定义通知栏传入的跳转或者传参之类
* @property bigRemoteViews
* @property smallRemoteViews
*/
class
NotificationBean
(
val
intent
:
Intent
,
val
bigRemoteViews
:
RemoteViews
,
val
smallRemoteViews
:
RemoteViews
)
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/
fcm
/NotificationHoverUtils.kt
→
app/src/main/java/com/base/locationsharewhite/
notification
/NotificationHoverUtils.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite.fcm
package
com.
example.mydemo.strategy.notification
import
android.content.Context
import
android.os.Handler
import
android.os.HandlerThread
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.utils.AppPreferences
import
com.base.locationsharewhite.utils.LogEx
import
com.example.mydemo.strategy.fcm.MsgMgr
object
NotificationHoverUtils
{
...
...
@@ -17,13 +15,7 @@ object NotificationHoverUtils {
/**
* 发送悬停通知
*/
fun
sendHoverNotification
(
context
:
Context
)
{
val
hoverCount
=
AppPreferences
.
getInstance
().
getString
(
"popup_hover_count"
,
"0"
).
toInt
()
val
hoverDelay
=
AppPreferences
.
getInstance
().
getString
(
"popup_hover_delay"
,
"0"
).
toLong
()
val
hoverStatus
=
AppPreferences
.
getInstance
().
getString
(
"popup_hover_status"
,
"0"
).
toInt
()
if
(
hoverStatus
==
0
)
return
fun
sendHoverNotification
(
context
:
Context
,
hoverCount
:
Int
,
hoverDelay
:
Int
)
{
if
(
handlerThread
==
null
)
{
handlerThread
=
HandlerThread
(
"NotificationHandlerThread"
)
handlerThread
?.
start
()
...
...
@@ -37,17 +29,10 @@ object NotificationHoverUtils {
}
for
(
i
in
1
..
hoverCount
)
{
val
time
=
i
*
hoverDelay
val
time
=
(
i
*
hoverDelay
*
1000
+
300
).
toLong
()
handler
?.
postDelayed
(
Runnable
{
LogEx
.
logDebug
(
TAG
,
"handler ${MyApplication.PAUSED_VALUE}"
)
if
(
MyApplication
.
PAUSED_VALUE
==
1
)
{
handler
?.
removeCallbacksAndMessages
(
null
)
return
@Runnable
}
if
(
MyApplication
.
PAUSED_VALUE
!=
1
)
{
LogEx
.
logDebug
(
TAG
,
"handler send notification"
)
NotificationUiUtil
.
setActionNotification
(
context
,
NotificationUiUtil
.
hoverActionId
)
}
//发送普通通知,不需要在悬停,这里就关闭了悬停
MsgMgr
.
sendNotification
(
context
,
MsgMgr
.
hoverActionId
,
0
)
},
time
)
}
}
...
...
app/src/main/java/com/base/locationsharewhite/notification/NotificationMgr.kt
0 → 100644
View file @
8b1c7c11
package
com.example.mydemo.strategy.notification
import
android.app.NotificationChannel
import
android.app.NotificationManager
import
android.app.PendingIntent
import
android.content.Context
import
android.content.Intent
import
android.graphics.drawable.Icon
import
android.os.Build
import
android.widget.RemoteViews
import
androidx.core.app.NotificationCompat
import
androidx.core.graphics.drawable.IconCompat
import
com.base.locationsharewhite.helper.ConstConfig
import
com.example.mydemo.R
import
kotlin.random.Random
/**
*通知管理类
*/
object
NotificationMgr
{
fun
init
(
context
:
Context
)
{
val
notificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
//创建channel
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
val
channel
=
NotificationChannel
(
ConstConfig
.
CHANNEL_ID
,
ConstConfig
.
CHANNEL_NAME
,
NotificationManager
.
IMPORTANCE_HIGH
)
channel
.
lockscreenVisibility
=
NotificationCompat
.
VISIBILITY_PUBLIC
channel
.
enableLights
(
false
)
channel
.
enableVibration
(
false
)
channel
.
vibrationPattern
=
longArrayOf
(
0
)
channel
.
setSound
(
null
,
null
)
notificationManager
.
createNotificationChannel
(
channel
)
}
}
fun
sendNotification
(
context
:
Context
,
intent
:
Intent
,
bigRemoteViews
:
RemoteViews
,
smallRemoteViews
:
RemoteViews
)
{
val
notificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
// Create the notification
val
builder
:
NotificationCompat
.
Builder
=
NotificationCompat
.
Builder
(
context
,
ConstConfig
.
CHANNEL_ID
)
//设置状态栏内的小图标
val
smallIcon
=
IconCompat
.
createFromIcon
(
context
,
Icon
.
createWithResource
(
context
,
ConstConfig
.
NOTIFICATION_LOGO
)
)
smallIcon
?.
let
{
builder
.
setSmallIcon
(
smallIcon
)
}
builder
.
setContentTitle
(
context
.
resources
.
getString
(
R
.
string
.
app_name
))
.
setContentText
(
"notification"
)
val
requestCode
=
Random
.
nextInt
(
1000
)
val
pendingIntent
=
PendingIntent
.
getActivity
(
context
,
requestCode
,
intent
,
PendingIntent
.
FLAG_IMMUTABLE
)
val
deleteIntent
=
PendingIntent
.
getBroadcast
(
context
,
requestCode
,
Intent
(
context
,
DeleteNotificationReceiver
::
class
.
java
),
PendingIntent
.
FLAG_IMMUTABLE
)
builder
.
setContentIntent
(
pendingIntent
)
.
setPriority
(
NotificationCompat
.
PRIORITY_MAX
)
.
setAutoCancel
(
true
)
.
setVibrate
(
longArrayOf
(
0
))
.
setSound
(
null
)
.
setDeleteIntent
(
deleteIntent
)
// 设置小视图
builder
.
setCustomContentView
(
smallRemoteViews
)
// 设置悬浮通知视图(Android 12 及以上)
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
S
)
{
builder
.
setCustomHeadsUpContentView
(
bigRemoteViews
)
}
// 设置大视图
builder
.
setCustomBigContentView
(
bigRemoteViews
)
notificationManager
.
notify
(
ConstConfig
.
NOTIFICATION_ID
,
builder
.
build
())
}
}
\ No newline at end of file
app/src/main/java/com/base/locationsharewhite/service/StayNotificationService.kt
View file @
8b1c7c11
package
com.
base.locationsharewhite
.service
package
com.
example.mydemo.strategy
.service
import
android.app.Notification
import
android.app.NotificationChannel
...
...
@@ -15,14 +15,10 @@ import android.os.IBinder
import
android.widget.RemoteViews
import
androidx.core.app.NotificationCompat
import
androidx.core.graphics.drawable.IconCompat
import
com.base.locationsharewhite.R
import
com.base.locationsharewhite.fcm.PopupConstObject
import
com.base.locationsharewhite.helper.EventUtils
import
com.base.locationsharewhite.helper.MyApplication
import
com.base.locationsharewhite.ui.main.MainActivity
import
com.base.locationsharewhite.ui.splash.SplashActivity
import
com.base.locationsharewhite.utils.LogEx
import
kotlin.random.Random
import
com.base.locationsharewhite.helper.ConstConfig
import
com.base.locationsharewhite.helper.GoogleSdkMgr
import
com.example.mydemo.MainActivity
import
com.example.mydemo.R
/**
...
...
@@ -61,72 +57,16 @@ class StayNotificationService : Service() {
fun
createPermanentNotification
(
context
:
Context
):
Notification
{
val
channelName
=
"P
DF Reader
Foreground Service Channel"
val
channelId
=
"
PDF_Reader_Service_Id
"
val
channelName
=
"P
ermanent
Foreground Service Channel"
val
channelId
=
"
permanent_channel
"
val
contentView
=
RemoteViews
(
context
.
packageName
,
R
.
layout
.
stay_notification_big
)
val
expendView
=
RemoteViews
(
context
.
packageName
,
R
.
layout
.
stay_notification_big
)
val
requestCode1
=
Random
.
nextInt
(
1800
)
val
intent1
=
Intent
(
context
,
SplashActivity
::
class
.
java
).
apply
{
putExtra
(
"actionId"
,
PopupConstObject
.
NOTIFICATION_ACTION_HOME
)
}
val
pendingIntent1
=
PendingIntent
.
getActivity
(
context
,
requestCode1
,
intent1
,
PendingIntent
.
FLAG_IMMUTABLE
)
contentView
.
setOnClickPendingIntent
(
R
.
id
.
ll_1
,
pendingIntent1
)
expendView
.
setOnClickPendingIntent
(
R
.
id
.
ll_1
,
pendingIntent1
)
val
requestCode2
=
Random
.
nextInt
(
1800
)
val
intent2
=
Intent
(
context
,
SplashActivity
::
class
.
java
).
apply
{
putExtra
(
"actionId"
,
PopupConstObject
.
NOTIFICATION_ACTION_MY_CODE
)
}
val
pendingIntent2
=
PendingIntent
.
getActivity
(
context
,
requestCode2
,
intent2
,
PendingIntent
.
FLAG_IMMUTABLE
)
contentView
.
setOnClickPendingIntent
(
R
.
id
.
ll_2
,
pendingIntent2
)
expendView
.
setOnClickPendingIntent
(
R
.
id
.
ll_2
,
pendingIntent2
)
val
requestCode3
=
Random
.
nextInt
(
1800
)
val
intent3
=
Intent
(
context
,
SplashActivity
::
class
.
java
).
apply
{
putExtra
(
"actionId"
,
PopupConstObject
.
NOTIFICATION_ACTION_SHARE
)
}
val
pendingIntent3
=
PendingIntent
.
getActivity
(
context
,
requestCode3
,
intent3
,
PendingIntent
.
FLAG_IMMUTABLE
)
contentView
.
setOnClickPendingIntent
(
R
.
id
.
ll_3
,
pendingIntent3
)
expendView
.
setOnClickPendingIntent
(
R
.
id
.
ll_3
,
pendingIntent3
)
val
requestCode4
=
Random
.
nextInt
(
1800
)
val
intent4
=
Intent
(
context
,
SplashActivity
::
class
.
java
).
apply
{
putExtra
(
"actionId"
,
PopupConstObject
.
NOTIFICATION_ACTION_SETTINGS
)
}
val
pendingIntent4
=
PendingIntent
.
getActivity
(
context
,
requestCode4
,
intent4
,
PendingIntent
.
FLAG_IMMUTABLE
)
contentView
.
setOnClickPendingIntent
(
R
.
id
.
ll_4
,
pendingIntent4
)
expendView
.
setOnClickPendingIntent
(
R
.
id
.
ll_4
,
pendingIntent4
)
val
builder
=
NotificationCompat
.
Builder
(
context
,
channelId
)
val
smallIcon
=
IconCompat
.
createFromIcon
(
context
,
Icon
.
createWithResource
(
MyApplication
.
context
,
R
.
mipmap
.
logo
context
,
ConstConfig
.
NOTIFICATION_LOGO
)
)
...
...
@@ -137,11 +77,17 @@ class StayNotificationService : Service() {
val
nfIntent
=
Intent
(
context
,
MainActivity
::
class
.
java
)
val
pendingIntent
=
PendingIntent
.
getActivity
(
context
,
0
,
nfIntent
,
PendingIntent
.
FLAG_IMMUTABLE
)
builder
.
setLargeIcon
(
BitmapFactory
.
decodeResource
(
context
.
resources
,
R
.
mipmap
.
logo
))
builder
.
setLargeIcon
(
BitmapFactory
.
decodeResource
(
context
.
resources
,
ConstConfig
.
NOTIFICATION_LOGO
)
)
builder
.
setContentTitle
(
context
.
resources
.
getString
(
R
.
string
.
app_name
))
builder
.
setContentIntent
(
pendingIntent
)
//设置PendingIntent
builder
.
setVisibility
(
NotificationCompat
.
VISIBILITY_PRIVATE
)
//设置通知公开可见
builder
.
setAutoCancel
(
false
)
builder
.
setOngoing
(
true
)
builder
.
setPriority
(
NotificationCompat
.
PRIORITY_MAX
)
//优先级为:重要通知
builder
.
setWhen
(
System
.
currentTimeMillis
())
builder
.
setCustomContentView
(
contentView
)
...
...
@@ -163,13 +109,13 @@ class StayNotificationService : Service() {
override
fun
onStartCommand
(
intent
:
Intent
?,
flags
:
Int
,
startId
:
Int
):
Int
{
LogEx
.
logDebug
(
TAG
,
"onStartCommand intent=$intent"
)
//
LogEx.logDebug(TAG, "onStartCommand intent=$intent")
if
(
intent
==
null
)
{
EventUtils
.
event
(
"onStartCommand"
,
"Foreground System auto launch intent=null isRunning=$isRunning"
)
//
EventUtils.event("onStartCommand", "Foreground System auto launch intent=null isRunning=$isRunning")
return
START_NOT_STICKY
}
if
(!
isRunning
)
{
LogEx
.
logDebug
(
TAG
,
"onStartCommand startForeground"
)
//
LogEx.logDebug(TAG, "onStartCommand startForeground")
startForeground
()
isRunning
=
true
...
...
@@ -179,11 +125,15 @@ class StayNotificationService : Service() {
}
private
fun
startForeground
()
{
val
notification
=
createPermanentNotification
(
MyApplication
.
context
)
val
notification
=
createPermanentNotification
(
GoogleSdkMgr
.
context
)
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
Q
)
{
startForeground
(
100
,
notification
,
ServiceInfo
.
FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
startForeground
(
ConstConfig
.
NOTIFICATION_PERMANENT_ID
,
notification
,
ServiceInfo
.
FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
}
else
{
startForeground
(
100
,
notification
)
startForeground
(
ConstConfig
.
NOTIFICATION_PERMANENT_ID
,
notification
)
}
isRunning
=
true
}
...
...
@@ -197,5 +147,4 @@ class StayNotificationService : Service() {
isRunning
=
false
super
.
onDestroy
()
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment