推送 Push\通知\渠道推送 JobScheduler 本地推送 WorkManager以及是否适用国内 后台执行限制

通知

通知概览如下:
创建通知
后台执行限制
后台优化
后台处理指南 对于我们的使用场景,Android官方推荐使用WorkManager
使用workManager实现每日定时推送通知
使用 WorkManager 实现定期通知
android 定时推送提醒,使用workManager实现每日定时推送通知

Demo工程

https://gitee.com/my739168148/local-push.git

通知的兼容性

自 Android 1.0 开始,通知系统界面以及与通知相关的 API 就在不断发展。如需在使用最新通知 API 功能的同时仍然支持旧版设备,请使用支持库通知 API:NotificationCompat 及其子类,以及 NotificationManagerCompat。这样一来,您就无需编写条件代码来检查 API 级别,因为这些 API 会为您代劳。

NotificationCompat 随着平台的发展不断更新,旨在纳入最新的方法。需要注意的是,某个方法在 NotificationCompat 中可用并不能保证可以在旧版设备上提供相应功能。在某些情况下,调用新引入的 API 会导致旧版设备出现空操作。例如,NotificationCompat.addAction() 仅在搭载 Android 4.1(API 级别 16)及更高版本的设备上显示操作按钮。

Android 4.1,API 级别 16

推出了展开式通知模板(称为通知样式),可以提供较大的通知内容区域来显示信息。用户可以通过单指向上/向下滑动的手势来展开通知。
还支持以按钮的形式向通知添加其他操作。
允许用户在设置中按应用关闭通知。

Android 4.4,API 级别 19 和 20

向 API 中添加了通知监听器服务。
API 级别 20 中新增了 Android Wear(现已更名为 Wear OS)支持。

Android 5.0,API 级别 21

  • 推出了锁定屏幕和提醒式通知。
  • 用户现在可以将手机设为勿扰模式,并配置允许哪些通知在设备处于“仅限优先事项”模式时打扰他们。
  • 向 API集添加了通知是否在锁定屏幕上显示的方法 (setVisibility()),以及指定通知文本的“公开”版本的方法。 添加了setPriority() 方法,告知系统通知的“干扰性”(例如,将其设为“高”可使通知以提醒式通知的形式显示)。
  • 向 Android Wear(现已更名为 Wear OS)设备添加了通知堆栈支持。使用 setGroup() 将通知放入堆栈。请注意,平板电脑和手机尚不支持通知堆栈。通知堆栈以后会称为组或 Bundle。

Android 7.0,API 级别 24

  • 重新设置了通知模板的样式以强调主打图片和头像。
  • 添加了三个通知模板:一个用于短信应用,另外两个用于借助展开式选项和其他系统装饰来装饰自定义内容视图。
  • 向手持设备(手机和平板电脑)添加了对通知组的支持。使用与 Android 5.0(API 级别 21)中推出的 Android Wear(现已更名为 Wear OS)通知堆栈相同的 API。
  • 用户可以使用内嵌回复功能直接在通知内进行回复(他们输入的文本将转发到通知的父应用)。

Android 8.0,API 级别 26

  • 现在必须将各个通知放入特定渠道中。
  • 现在,用户可以按渠道关闭通知,而非关闭来自某个应用的所有通知。
  • 包含有效通知的应用将在主屏幕/启动器屏幕上相应应用图标的上方显示通知“标志”。
  • 现在,用户可以从抽屉式通知栏中暂停某个通知。您可以为通知设置自动超时时间。
  • 您还可以设置通知的背景颜色。
  • 部分与通知行为相关的 API 已从 Notification 移至 NotificationChannel。例如,在搭载 Android 8.0 及更高版本的设备中,使用 NotificationChannel.setImportance(),而非NotificationCompat.Builder.setPriority()。

Android 13.0,API 级别 33

  • 添加了一项运行时权限。若要让您的应用能够发送非豁免通知,用户必须向您的应用授予此权限。

本地推送

顾虑1---- 后台执行限制

Android 8.0(API 级别 26)对应用在后台运行时可以执行的操作施加了限制。

在后台中运行的 Service 会消耗设备资源,这可能会降低用户体验。 为了缓解这一问题,系统对这些 Service 施加了一些限制。

系统可以区分前台和后台应用。 (用于 Service 限制目的的后台定义与内存管理使用的定义不同;一个应用按照内存管理的定义可能处于后台,但按照能够启动 Service 的定义又处于前台。)如果满足以下任意条件,应用将被视为处于前台:

  • 具有可见 Activity(不管该 Activity 已启动还是已暂停)。
  • 具有前台 Service。
  • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个 Service,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的 Service,那么该应用处于前台:
    - IME
    - 壁纸 Service
    - 通知侦听器
    - 语音或文本 Service
    如果以上条件均不满足,应用将被视为处于后台。

处于前台时,应用可以自由创建和运行前台与后台 Service。 进入后台时,在一个持续数分钟的时间窗内,应用仍可以创建和使用 Service。 在该时间窗结束后,应用将被视为处于空闲状态。 此时,系统将停止应用的后台 Service,就像应用已经调用 Service 的 Service.stopSelf() 方法一样。

在这些情况下,后台应用将被置于一个临时白名单中并持续数分钟。 位于白名单中时,应用可以无限制地启动 Service,并且其后台 Service 也可以运行。 处理对用户可见的任务时,应用将被置于白名单中,例如:

  • 处理一条高优先级 Firebase 云消息传递 (FCM)消息。
  • 接收广播,例如短信/彩信消息。
  • 从通知执行 PendingIntent。
  • 在 VPN 应用将自己提升为前台进程前开启 VpnService。

JobScheduler

JobScheduler是Android中的一个调度器,用于在特定条件下执行后台任务。它可以用于实现应用在被杀死后仍能推送消息的功能。

要使用JobScheduler实现应用被杀死后仍能推送消息,你需要以下步骤:
1、创建一个继承自JobService的类,用于执行后台任务。这个类负责在后台执行任务并推送消息。

public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        // 在这里执行后台任务和消息推送逻辑
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}

2、在你的应用中注册这个JobService。在AndroidManifest.xml文件中添加以下代码:

<service
    android:name=".MyJobService"
    android:permission="android.permission.BIND_JOB_SERVICE" />

3、在你的应用中调用JobScheduler来安排任务。你可以在合适的时机调用以下代码来安排任务:

JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
ComponentName componentName = new ComponentName(this, MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, componentName)
        .setRequiresCharging(true) // 设置任务的条件,例如需要充电时执行
        .setPersisted(true) // 设置任务在设备重启后是否继续执行
        .build();
jobScheduler.schedule(jobInfo);

实现方案——WorkManager

基于WorkManager实现本地推送。
WorkerManager实现本地推送时,需要自启动权限,因为推送通知消息是应用自身通知的。
workerManager不会触发Activity的onCreate,但是会触发Application的onCreate,Application的onCreate触发后,会触发Service或者receiver?
在这里插入图片描述

2023-07-19 20:17:58.108 975-975/? D/Zygote: Forked child process 13725
2023-07-19 20:17:58.110 1887-2484/? I/ActivityManager: Start proc 13725:cn.jj.localpush/u0a819 for next_app {cn.jj.localpush/cn.jj.localpush.MainActivity}
2023-07-19 20:17:58.111 1887-2484/? D/OplusUIFirst_FB: cn.jj.localpush proc start: 10819 13725 false cn.jj.localpush
2023-07-19 20:17:58.130 13725-13725/? I/cn.jj.localpush: Late-enabling -Xcheck:jni
2023-07-19 20:17:58.154 13725-13725/? E/cn.jj.localpush: Unknown bits set in runtime_flags: 0x40000000
2023-07-19 20:17:58.158 18098-18108/? I/adbd: jdwp connection from 13725
2023-07-19 20:17:58.163 13725-13725/? I/OneTrace: Mark active for pid=13725? true
2023-07-19 20:17:58.163 13725-13725/? D/cutils-dev: otrace_set_tracing_enabled? true
2023-07-19 20:17:58.167 13725-13770/? D/cutils-dev: properties changed in otrace_seq_number_changed!
2023-07-19 20:17:58.177 13725-13725/? V/studio.deploy: Startup agent attached to VM
2023-07-19 20:17:58.177 13725-13725/? V/studio.deploy: No existing instrumentation found. Loading instrumentation from instruments-88564b4d.jar
2023-07-19 20:17:58.180 13725-13725/? W/cn.jj.localpush: DexFile /data/data/cn.jj.localpush/code_cache/.studio/instruments-88564b4d.jar is in boot class path but is not in a known location
2023-07-19 20:17:58.183 13725-13725/? V/studio.deploy: Applying transforms with cached classes
2023-07-19 20:17:58.206 13725-13725/? W/cn.jj.localpush: Redefining intrinsic method java.lang.Thread java.lang.Thread.currentThread(). This may cause the unexpected use of the original definition of java.lang.Thread java.lang.Thread.currentThread()in methods that have already been compiled.
2023-07-19 20:17:58.206 13725-13725/? W/cn.jj.localpush: Redefining intrinsic method boolean java.lang.Thread.interrupted(). This may cause the unexpected use of the original definition of boolean java.lang.Thread.interrupted()in methods that have already been compiled.
2023-07-19 20:17:58.215 13725-13725/? D/CompatibilityChangeReporter: Compat change id reported: 171979766; UID 10819; state: ENABLED
2023-07-19 20:17:58.215 13725-13725/? I/oplus.android.OplusFrameworkFactoryImpl: get feature:IOplusAutoResolutionFeature
2023-07-19 20:17:58.215 13725-13725/? I/oplus.android.OplusFrameworkFactoryImpl: getOplusAutoResolutionFeature
2023-07-19 20:17:58.275 13725-13725/? I/OplusFeatureCache: Milliseconds spent on init(): 59
2023-07-19 20:17:58.280 13725-13725/cn.jj.localpush D/CompactWindowAppManager: initCompactApplicationInfo  MODE_COMPACT  
2023-07-19 20:17:58.346 13725-13725/cn.jj.localpush W/libc: Access denied finding property "ro.odm.prev.product.name"
2023-07-19 20:17:58.361 13725-13725/cn.jj.localpush D/LoadedApk: mApplicationInfo overrideDisplayId:null
2023-07-19 20:17:58.366 13725-13725/cn.jj.localpush W/ziparchive: Unable to open '/data/data/cn.jj.localpush/code_cache/.overlay/base.apk/classes3.dm': No such file or directory
2023-07-19 20:17:58.367 13725-13725/cn.jj.localpush W/ziparchive: Unable to open '/data/app/~~ND6I7AkQy9joo_T1SaZaIQ==/cn.jj.localpush-K36ru8wfOsk3TnC-vnUD1g==/base.dm': No such file or directory
2023-07-19 20:17:58.367 13725-13725/cn.jj.localpush W/ziparchive: Unable to open '/data/app/~~ND6I7AkQy9joo_T1SaZaIQ==/cn.jj.localpush-K36ru8wfOsk3TnC-vnUD1g==/base.dm': No such file or directory
2023-07-19 20:17:58.679 13725-13725/cn.jj.localpush I/Quality: ActivityThread: createClassLoader delay 317 /data/app/~~ND6I7AkQy9joo_T1SaZaIQ==/cn.jj.localpush-K36ru8wfOsk3TnC-vnUD1g==/base.apk 13725
2023-07-19 20:17:58.683 13725-13725/cn.jj.localpush I/Quality: ActivityThread: createOrUpdateClassLoaderLocked delay 322 cn.jj.localpush 13725
2023-07-19 20:17:58.746 13725-13725/cn.jj.localpush V/GraphicsEnvironment: ANGLE Developer option for 'cn.jj.localpush' set to: 'default'
2023-07-19 20:17:58.747 13725-13725/cn.jj.localpush V/GraphicsEnvironment: ANGLE GameManagerService for cn.jj.localpush: false
2023-07-19 20:17:58.748 13725-13725/cn.jj.localpush V/GraphicsEnvironment: App is not on the allowlist for updatable production driver.
2023-07-19 20:17:58.758 13725-13725/cn.jj.localpush D/NetworkSecurityConfig: No Network Security Config specified, using platform default
2023-07-19 20:17:58.760 13725-13725/cn.jj.localpush D/NetworkSecurityConfig: No Network Security Config specified, using platform default
2023-07-19 20:17:58.781 13725-13725/cn.jj.localpush D/WM-WrkMgrInitializer: Initializing WorkManager with default configuration.
2023-07-19 20:17:58.811 1887-4093/? W/PackageManager: package unknown uid 10819 pid 13725 call SetEnabledSetting(cn.jj.localpush component = androidx.work.impl.background.systemjob.SystemJobService, 1, 0)
2023-07-19 20:17:58.836 13725-13725/cn.jj.localpush I/JJWorld.MyApplication: MyApplication onCreate......
2023-07-19 20:17:58.838 13725-13725/cn.jj.localpush D/OplusActivityManager: get AMS extension: android.os.BinderProxy@99cd4ca
2023-07-19 20:17:58.841 1887-3837/? I/OplusHansManager: freeze uid: 10819 cn.jj.localpush pids: [13725] scene: LcdOn from: Preload_F
2023-07-19 20:19:06.707 1887-1887/? I/OplusHansManager: unfreeze uid: 10819 cn.jj.localpush pids: [13725] reason: Preload_UF scene: LcdOn
2023-07-19 20:19:06.716 13725-13788/cn.jj.localpush I/Quality: SlowSQLite: /d9a0facb11102c97f3b4af6fce499434/ cost= /67869
2023-07-19 20:19:06.740 13725-13761/cn.jj.localpush W/System: A resource failed to call close. 
2023-07-19 20:19:06.778 13725-13788/cn.jj.localpush D/CompatibilityChangeReporter: Compat change id reported: 160794467; UID 10819; state: ENABLED
2023-07-19 20:19:06.800 13725-13788/cn.jj.localpush D/CompatibilityChangeReporter: Compat change id reported: 194532703; UID 10819; state: ENABLED
2023-07-19 20:19:06.876 13725-13874/cn.jj.localpush I/JJWorld.MyWorkManager: doWork.....
2023-07-19 20:19:06.906 13725-13788/cn.jj.localpush I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=85711d49-0d34-45e7-bf15-b1f00cb1d5d7, tags={ cn.jj.localpush.MyWorkManager } ]
2023-07-19 20:19:06.909 1887-4107/? W/PackageManager: package unknown uid 10819 pid 13725 call SetEnabledSetting(cn.jj.localpush component = androidx.work.impl.background.systemalarm.RescheduleReceiver, 2, 0)
2023-07-19 20:19:16.724 1887-3803/? I/OplusHansManager: freeze uid: 10819 cn.jj.localpush pids: [13725] scene: LcdOn

需要引入资源

dependencies {
    implementation "androidx.work:work-runtime:2.7.0"
}

无额外权限

测试

实际测试,测试设备OPPO Find N,通知渠道优先级为 IMPORTANCE_DEFAULT,杀端时间1分钟:
1、应用在后台、杀端(无自启动权限)情况下,收不到推送,期间的推送消息在应用回前台后展示。
2、应用杀死后。OPPO FIND N设备开启 允许完全后台行为时。无法收到本地推送消息。
3、应用杀死后。开启自启动权限与允许完全后台行为时。可以收到本地推送消息。
4、应用杀死后。开启自启动权限时。可以收到本地推送消息。
5、应用在前台,可以收到推送消息。

注意:
1、发送多条数据的表现。最新的通知消息会覆盖上一条通知消息。
2、WorkManager会在设备空闲时执行任务,所以不保证任务能够准确按照设定的时间执行。任务可能会延后执行。

实际测试,测试设备OPPO Find N Android13,通知渠道优先级为 IMPORTANCE_HIGH,杀端时间1分钟:
1、应用在后台,收不到推送消息。
2、应用杀死后,没有开特殊权限的话,收不到推送。
3、应用杀死后。OPPO FIND N设备开启 自启动权限与允许完全后台行为时。可以收到本地推送消息。
4、应用杀死后。OPPO FIND N设备开启 自启动权限时。可以收到本地推送消息。
5、应用杀死后。OPPO FIND N设备开启 允许完全后台行为时。无法收到本地推送消息。
6、应用在前台,可以收到推送消息。

WorkManager是基于系统的JobScheduler和AlarmManager来调度任务的,而这些系统组件在应用处于后台时的行为是受限的。具体来说,如果应用处于后台,WorkManager可能会受到以下限制:

  • 1、执行时间延迟:当应用处于后台时,系统可能会推迟或延迟任务的执行,以降低对设备性能和电池寿命的影响。这意味着任务可能不会按照预期的时间立即执行。

  • 2、网络限制:在Android9及更高版本中,应用在后台时访问网络会受到限制。这意味着在后台时,应用可能无法建立网络连接或发送/接收网络请求。这也可能导致无法及时收到推送消息。

  • 3、自启动权限:某些设备厂商对后台任务的执行进行了更严格的限制,并要求用户授予自启动权限。这意味着除非用户明确允许应用在后台启动任务,否则任务可能无法正常执行。

WorkerManager实战

应用在后台,可以打印日志

   public void WorkerManagerTest() {
//        MyWorkManager myWorkManager = new MyWorkManager(activity,null);
//
//        Constraints constraints = null;
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//            constraints = new Constraints.Builder().setTriggerContentMaxDelay(1 * 60,
//                    TimeUnit.SECONDS).build();
//        }

        @SuppressLint("IdleBatteryChargingConstraints") Constraints constraints = new Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)  // 网络状态
                .setRequiresBatteryNotLow(true)                 // 不在电量不足时执行
                .setRequiresCharging(true)                      // 在充电时执行
                .setRequiresStorageNotLow(true)                 // 不在存储容量不足时执行                 // 在待机状态下执行,需要 API 23
                .build();

        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorkManager.class)
                .setInitialDelay(20 * 1, TimeUnit.SECONDS)
                .setConstraints(constraints)
                .build();
        WorkManager.getInstance(activity).enqueue(workRequest);
        Log.i(TAG, "WorkerManagerTest working");
    }
2023-08-20 10:45:41.947 20841-20841/cn.jj.localpush I/JJWorld.MyApplication: MyApplication onCreate......
2023-08-20 10:45:42.039 20841-20841/cn.jj.localpush I/JJWorld.MainActivity: createNotificationChannel SDK version is ok....
2023-08-20 10:45:46.286 20841-20841/cn.jj.localpush I/JJWorld.MainActivity: WorkerManagerTest working
2023-08-20 10:46:06.375 20841-20950/cn.jj.localpush I/JJWorld.MyWorkManager: doWork

杀端

日志不会打印

杀端 开启自启动权限、完全后台行为

会打印日志

2023-08-20 11:11:32.873 29779-29779/cn.jj.localpush I/JJWorld.MyApplication: MyApplication onCreate......
2023-08-20 11:11:32.995 29779-29808/cn.jj.localpush I/JJWorld.MyWorkManager: doWork

WorkerManager在国内手机上不生效

此篇文章结尾注意点与我实际测试中的感受相似。
WorkerManager在国内手机上测试时并没有生效。应用杀死后,workerManager的所有动作都会停止。

google官方问题讨论

workerManager在国内很多厂商上,确实会不生效。

魅族渠道

魅族渠道收到Push消息后的启动顺序如下,

  1. applicaition的oncreate
  2. MeizuPushReceiver中的onNotificationClicked
  3. 然后是主acitivity的onCreate.
    此外,应用在后台以及应用杀端情况下,魅族的主activity的onDestory会触发,每次应用拉起前端界面都是onCreate。

小米渠道

服务端发送消息类型

自定义点击动作消息

小米渠道拉起首页方式

小米收到的自定义参数可以在

public void onNotificationMessageClicked(Context context, MiPushMessage message)

中解析。解析之后拉起应用首页时,Context的类型为application,因此,需要拉起首页的intent消息中要添加下面的Flag标志位,表示如果当前没有存在activity的task任务栈的话,则创建task任务栈,如果存在task任务栈,则将activity压入task任务栈。

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

不同Android版本差异

小米渠道服务端通过API发送自定义点击动作消息后,不同Android版本的小米手机表现不一样。对于android8.0的小米5s来说,点击推送消息之后不会启动activity,而对于android12.0的红米K50来说,点击推送消息之后,会启动一个activity。

Android 8.0

在这里插入图片描述

Android 12.0

点击推送消息后,android12.0手机会创建一个activity. 类名为

com.xiaomi.mipush.sdk.NotificationClickedActivity

在这里插入图片描述
因为小米渠道Android12版本在点击推送消息时会拉起activity,因此小米渠道没法判断无法根据应用在前台或后台,从而进行不同的处理,比如应用在前台时,仅传递自定义参数不拉起界面,应用在后台时,即传递参数又拉起界面。所以小米渠道仅判断杀端与不杀端的情况。
而华为和OPPO可以在MsgBus中判断应用在前台或者在后台,因此,可以根据应用在前台和后台的结果进行把不同逻辑的处理。

从后台拉起activity界面的方式

从后台拉起指定页面有两种常见的方式。

基于ActivityManager的moveTaskToFront方式

该方式的核心思想是获取对应于当前应用的任务栈,获取到任务栈之后使用将任务栈推到应用前台。

ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

当context为activity时,任务栈可以通过getTaskId()直接获取,此时任务从后台到前台的语句为:

am.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_WITH_HOME);

当context为applicaition时,任务栈没法直接获取,需要利用getRunningTasks判断当前运行的任务栈。

List<ActivityManager.RunningTaskInfo> taskList = am.getRunningTasks(100);

如果其中任务栈对应的package名称与当前程序对应的packageName匹配的话,则将此task推到前台。

for (ActivityManager.RunningTaskInfo rti : taskList) {
    //找到当前应用的task,并启动task的栈顶activity,达到程序切换到前台
    if (rti.topActivity.getPackageName().equals(context.getPackageName())) {
        am.moveTaskToFront(rti.id, 0);
        hasLaunch = true;
    }
}

基于Intent的startActivity方式

此工具类的getLaunchIntentForPackage方法仅需packageName以及application类型的Context,就可以获取打开启动页activity的intent。

package cn.jj.push.aggpushsdk.utils;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;

import java.time.temporal.TemporalAccessor;
import java.util.List;

public class LaunchUtils {

    private static final String TAG = "JJPushSDK.LaunchUtils";

    public static Intent getLaunchIntentForPackage(String packageName, Context context) {
        // First see if the package has an INFO activity; the existence of
        // such an activity is implied to be the desired front-door for the
        // overall package (such as if it has multiple launcher entries).
        PackageManager pm = context.getPackageManager();

        Intent intentToResolve = new Intent();
        intentToResolve.setAction(Intent.ACTION_MAIN);
        intentToResolve.addCategory(Intent.CATEGORY_INFO);
        intentToResolve.setPackage(packageName);
        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);

        // Otherwise, try to find a main launcher activity.
        if (ris == null || ris.size() <= 0) {
            // reuse the intent instance
            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
            intentToResolve.setPackage(packageName);
            ris = pm.queryIntentActivities(intentToResolve, 0);
        }
        if (ris == null || ris.size() <= 0) {
            return null;
        }
        Intent intent = new Intent(intentToResolve);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName(ris.get(0).activityInfo.packageName,
                ris.get(0).activityInfo.name);

        LogUtils2.i(TAG,"xiaomi start. packageName:" + ris.get(0).activityInfo.packageName);
        LogUtils2.i(TAG,"xiaomi start. activityName:" + ris.get(0).activityInfo.name);

        return intent;
    }
}

intent获取到之后,打开首页就可以了

 Intent launchIntentForPackage = LaunchUtils.getLaunchIntentForPackage(getPackageName(), this);
 startActivity(launchIntentForPackage);

华为与OPPO推送

华为与OPPO推送,可以选择打开指定页面的方式,然后从指定页面的intent中解析自定义参数信息。
为了与华为、oppo的意图过滤器匹配,可以在创建一个activity,在activity的oncreate中解析自定义参数信息,通过在oncreate的结束,调用finsh方法,将activity关闭。

  1. oncreate 通过intent 解析自定义参数
  2. 利用activity本身的context实现页面的跳转,跳转到启动页,通过将自定义参数存储。
  3. oncreate的结束,调用finish(),关闭当前的中间activity。

注意:此activity不设置ContentView,因此,此activity不会有界面。
通常情况下的activity都包括了setContentView语句。

setContentView(R.layout.activity_main);
@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LogUtils2.i(TAG, "onCreate");
		// intent参数解析
		// 页面跳转
		finish();  	

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python是一种功能强大的编程语言,具有简单易学、灵活性高等特点,非常适合开发自动化任务。Push Plus是一款推送服务,可以实现向微信、QQ、邮箱等多个平台推送消息的功能。在日常学习和工作中,很多人需要及时掌握每日任务完成情况,这就需要使用Python来实现Push Plus推送任务完成情况。 首先,需要在Push Plus官网上注册账号,并创建自己的推送通道。然后,可以使用Python的requests库来发送POST请求,将任务完成情况推送Push Plus通道中。代码如下: ```python import requests # Push Plus通道Token token = 'your_token' # 推送标题 title = '每日任务完成情况' # 推送内容 content = '今日任务已完成!' # 推送方式 template = 'html' # 发送POST请求 response = requests.post('http://pushplus.hxtrip.com/send', data={'token': token, 'title': title, 'content': content, 'template': template}) ``` 其中,token是在Push Plus官网上创建的推送通道的Token,title是推送标题,content是推送内容,template是推送消息的格式,可以是txt或html。以上代码使用的是html格式。 为了实现每日自动推送任务完成情况,可以利用Python的定时任务库,比如APScheduler,设置每日定时发送推送请求。代码如下: ```python from apscheduler.schedulers.blocking import BlockingScheduler # 创建定时任务 scheduler = BlockingScheduler() # 定义任务 def push_task(): # Push Plus通道Token token = 'your_token' # 推送标题 title = '每日任务完成情况' # 推送内容 content = '今日任务已完成!' # 推送方式 template = 'html' # 发送POST请求 response = requests.post('http://pushplus.hxtrip.com/send', data={'token': token, 'title': title, 'content': content, 'template': template}) print(response.text) # 添加定时任务,每天8点执行 scheduler.add_job(push_task, 'cron', hour=8) # 启动定时任务 scheduler.start() ``` 以上代码使用APScheduler定时任务库,并设置每天早上8点执行任务。当任务完成后,会自动将任务完成情况推送Push Plus通道中,从而方便在手机或电脑上收到及时的提醒。 综上所述,Python和Push Plus可以很好地配合使用,实现每日任务完成情况的自动推送。有了这个工具,我们可以更好地管理自己的工作和学习,提高效率和自律性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学知识拯救世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值