Android 集成firebase 推送(FCM)

news2024/12/28 4:30:41

1,集成firebase 基础

1>googleService文件

2>项目级gradle

3>app级gradle

4>setting 

2,推送相关

重点:

源文档:设置 Firebase Cloud Messaging 客户端应用 (Android) (google.com)

/**
 * 监听推送的消息
 * 三种情况:
 * 1,通知时:
 * 当应用处于前台的时候,推送的消息会走onMessageReceived方法,处于后台时走系统托盘。
 * 2,数据时:
 * 当应用处于前、后台的时候,会走onMessageReceived方法。
 * 3,通知且携带数据:
 * 当应用处于前台的时候,推送的消息会走onMessageReceived方法,处于后台时,通知走系统托盘,数据走Intent 的 extra 中(点击通知栏后)。
 */

1>清单文件

2>MyFirebaseMessagingService类

/**
 * 推送数据对通知的影响
 * 1,如果我们推送的数据 notification 对应的数据 不为空,那么我们接收消息就需要分为两种情况,
 * 前台和后台,如果App当前状态为前台,那么 onMessageReceived 方法就会被调用,
 * 后续我们自己拿到对用的数据进行通知栏的显示,如果App当前状态为后台的话 那么我们无需自己写 sdk会自己弹出。
 *
 *,2,如果我们推送的数据 notification 对应的数据为空,把所有的数据放置到data 字段里面,
 * 那么sdk不会为我们弹出通知,这时候无论App在前台还是后台都会调用 onMessageReceived ,
 * 这时候我们自己需要处理通知栏的ui 显示。这种情况一般用于自定义通知栏ui 的时候。
 */

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    /**
     * 监听推送的消息
     * 三种情况:
     * 1,通知时:
     * 当应用处于前台的时候,推送的消息会走onMessageReceived方法,处于后台时走系统托盘。
     * 2,数据时:
     * 当应用处于前、后台的时候,会走onMessageReceived方法。
     * 3,通知且携带数据:
     * 当应用处于前台的时候,推送的消息会走onMessageReceived方法,处于后台时,通知走系统托盘,数据走Intent 的 extra 中(点击通知栏后)。
     */
    @Override
    public void onMessageReceived(@NonNull RemoteMessage message) {

        String testDemo = "0";//测试数据,后端自定义消息/或控制台测试时输入键值,时传递来 “键”-“值” 中的 值
//        Map<String, String> remoteMessageMap = message.getData();
        if (message.getData() != null && !message.getData().isEmpty()) {//不自定义消息,getData为空
            if (message.getData().size() > 0) {
                testDemo = message.getData().get("testDemo");//“键”-“值” 中的 键

            }
        }

        if (message.getNotification() != null && !message.getNotification().getTitle().isEmpty() && !message.getNotification().getBody().isEmpty()) {
//            sendNotification(message.getNotification().getTitle(), message.getNotification().getBody(), testDemo);
            String click_action = message.getNotification().getClickAction();
            sendNotification(message.getNotification().getTitle(), message.getNotification().getBody(), testDemo, click_action);
        }


    }


    /**
     * 当有新的Firebase token 时的回调
     * 第一次安装app 获取到的 pushtoken
     */
    @Override
    public void onNewToken(@NonNull String token) {
        //token 传递给后端!!
        Log.e("测试", "onNewToken =" + token);
    }

    /**
     * 自定义通知
     *
     * @param messageBody
     */
    private void sendNotification(String messageTitle, String messageBody, String testDemo, String click_action) {
        Intent intent = prepareIntent(click_action);
//    private void sendNotification(String messageTitle, String messageBody, String testDemo) {
//        Intent intent = new Intent(this, MainActivity.class);

        String channelID = getResources().getString(R.string.default_notification_channel_id);//渠道ID
        String channelName = getResources().getString(R.string.default_notification_channel_name);//渠道名称

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        if (testDemo != null && !testDemo.isEmpty()) {
            intent.putExtra("testDemo", testDemo);

        }

        int uniqueInt = (int) (System.currentTimeMillis() & 0xff);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueInt /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationCompat.Builder notificationBuilder;
        //android 8 开始要 创建通知渠道,否则通知栏不弹出
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationBuilder = new NotificationCompat.Builder(this, channelID);
            NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
            notificationManager.createNotificationChannel(channel);
        } else {
            notificationBuilder = new NotificationCompat.Builder(this);
        }

        //设置title
        if (messageTitle != null && !messageTitle.isEmpty()) {
            notificationBuilder.setContentTitle(messageTitle);
        } else {
            notificationBuilder.setContentTitle(getResources().getString(R.string.app_name));
        }

        //设置body
        if (messageBody != null && !messageBody.isEmpty()) {
            notificationBuilder.setContentText(messageBody);
        }
//        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        notificationBuilder
                .setSmallIcon(R.drawable.icon_return)//设置通知栏的小图标,必需设置,否则crash
                .setAutoCancel(true)//点击通知后,通知自动消失
                .setWhen(System.currentTimeMillis())// 设置通知时间,此事件用于通知栏排序
                .setPriority(NotificationCompat.PRIORITY_HIGH)// 设置优先级,低优先级可能被隐藏
//                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);//设置通知栏被点击时的事件

        notificationManager.notify(uniqueInt /* ID of notification */, notificationBuilder.build());

    }

    public Intent prepareIntent(String clickAction) {
        Intent intent;
        boolean isAppInBackground;
        isAppInBackground = ProcessJudgmentHelper.isRunBackground(this);
        if (isAppInBackground) {
            intent = new Intent(this, MainActivity.class);
        } else {
            intent = new Intent(clickAction);
        }

        return intent;
    }

    /**
     * 1,如果未开启通知,则跳转到通知设置界面,点击之后就需要跳转到 APP的通知设置界面,
     * 对应的Action是:Settings.ACTION_APP_NOTIFICATION_SETTINGS, 这个Action是 API 26 后增加的。
     * 2,如果在部分手机中无法精确的跳转到APP对应的通知设置界面,我们就考虑直接跳转到APP信息界面,
     * 对应的Action是:Settings.ACTION_APPLICATION_DETAILS_SETTINGS。
     *
     */

}

4>主启动Activity(清单文件里设置 <action android:name="android.intent.action.MAIN" /> 的Activity)


/**
 * 1,清单文件里设置 <action android:name="android.intent.action.MAIN" /> 的Activity,一般是Splish 闪屏页。
 * 在onCreate() 方法里 获取用户PushToken,调用接口传给自己的后端,以防有变化。
 * 2,如果是自定义消息(当后端或者控制台设置响应的data 键值)在onResume() 方法里 使用intent 获取到对应的值,进行相关操作,
 * 例如:根据约定值 进行响应页面的跳转。
 *
 *
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestPer();

        try {
            boolean goolgePlayServiceAvailable = FirebaseManager.getInstance().isGoolgePlayServiceAvailable(this);
            if (goolgePlayServiceAvailable) {
                uploadPushToken();
            } else {
                Log.e("测试", "谷歌服务不可用");
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("测试", "谷歌服务异常");

        }
    }


    @Override
    protected void onResume() {
        super.onResume();
        Intent intent = getIntent();
        //当后端或者控制台设置自定义消息后,点击通知时能获取到对应的值
        String testDemo = intent.getStringExtra("testDemo");

        if (testDemo != null && !testDemo.isEmpty()) {
            //如有特殊情形,要判断是否登录,没登录跳转登录页
//            if(){
//            }
            if (testDemo.equals("66")) {
                Intent intentSeconActivity = new Intent(this, SeconActivity.class);
                startActivity(intentSeconActivity);
                finish();
            }
        }

    }

    /**
     * 上传push token
     * 正常情况下每次启动 都会获取到!
     */
    private void uploadPushToken() {
        FirebaseMessaging.getInstance().getToken()
                .addOnCompleteListener(new OnCompleteListener<String>() {
                    @Override
                    public void onComplete(@NonNull Task<String> task) {
                        if (!task.isSuccessful()) {
                            Log.e("测试", "Fetching FCM registration token failed", task.getException());
                            return;
                        }

                        // Get new FCM registration token
                        String token = task.getResult();
                        Log.e("测试", "MainActivity token =" + token);

                    }
                });
    }

    /**
     * android 高版本请求推送权限
     */
    private void requestPer() {
        XXPermissions.with(this)
                // 申请单个权限
                .permission(Permission.POST_NOTIFICATIONS)
                .request(new OnPermissionCallback() {

                    @Override
                    public void onGranted(List<String> permissions, boolean all) {

                    }

                    @Override
                    public void onDenied(List<String> permissions, boolean never) {
                        if (never) {

                        } else {
                        }
                    }
                });
    }
}

==================结束===============

工具方法:
 

    /** 判断程序是否在后台运行 */
    public static boolean isRunBackground(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.processName.equals(context.getPackageName())) {
                if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
                    // 表明程序在后台运行
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1375592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

php中常用的几个安全函数

1. mysql_real_escape_string() 这个函数对于在PHP中防止SQL注入攻击很有帮助&#xff0c;它对特殊的字符&#xff0c;像单引号和双引号&#xff0c;加上了“反斜杠”&#xff0c;确保用户的输入在用它去查询以前已经是安全的了。但你要注意你是在连接着数据库的情况下使用这个…

抵御爬虫的前线护盾:深度解读验证码技术的演变历程

一.前言 在当今信息技术迅速发展的背景下&#xff0c;网站和在线服务面临着日益增长的自动化访问威胁&#xff0c;这些大多来自于各类爬虫程序。这种大量的自动化访问不仅对网站的正常运行构成压力&#xff0c;还可能导致敏感数据的泄露&#xff0c;甚至被用于不正当竞争和恶意…

微内核、宏内核、混合内核,三者到底有什么区别?

最近几年&#xff0c;随着国内大厂纷纷发布自研操作系统&#xff0c;大家对这些操作系统的出身和相貌吵得不可开交。然而&#xff0c;本文并不打算陷入这种无尽的争论之中。 在计算机技术的发展历程中&#xff0c;所有的技术都是在不断的迭代和发展中形成的&#xff0c;无论是…

win10在启动游戏时报错,提示“d3dx9_25.dll文件丢失”,怎么办?d3dx9_25.dll丢失如何自动修复

一、d3dx9_25.dll文件是什么&#xff1f; d3dx9_25.dll是DirectX的一部分&#xff0c;DirectX是一种由微软开发的专门处理与多媒体、游戏程序和视频相关的应用程序接口。d3dx9_25.dll文件是DirectX9中一个重要的dll文件&#xff0c;主要负责处理3D图形程序&#xff0c;作用是帮…

python高校舆情分析系统+可视化+情感分析 舆情分析+Flask框架(源码+文档)✅

毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&#xff0c;点赞、关注不迷路&#xff0c;大家在毕设选题&#xff…

图片双线性插值原理解析与代码 Python

一、原理解析 图片插值是图片操作中最常用的操作之一。为了详细解析其原理&#xff0c;本文以 33 图片插值到 55 图片为例进行解析。如上图左边蓝色方框是 55 的目标图片&#xff0c;右边红色方框是 33 的源图片。上图中&#xff0c;蓝/红色方框是图片&#xff0c;图片中的蓝/红…

记录误删除docker中极狐gitlab容器恢复过程

如题一次误操作导致删除了docker中极狐gitlab容器恢复过程 情况说明 创建容器时&#xff0c;我是用的是极狐官网推荐安装的步骤&#xff0c;具体按照官网步骤走就行 sudo docker run --detach \--hostname gitlab.example.com \--publish 443:443 --publish 80:80 --publish …

java通过okhttp方式实现https请求的工具类(绕过证书验证)

目录 一、引入依赖包二、okhttp方式实现的https请求工具类2.1、跳过证书配置类2.2、okhttp方式的 https工具类 三、测试类 一、引入依赖包 引入相关依赖包 <!--okhttp依赖包--> <dependency><groupId>com.squareup.okhttp3</groupId><artifactId>…

书生·浦语大模型实战营-学习笔记2

目录 轻松玩转书生浦语大模型趣味Demo1. 大模型及 InternLM 模型介绍2. InternLM-Chat-7B 智能対话 Demo3. Lagent 智能体工具调用 Demo4. 浦语•灵笔图文创作理解 Demo5. 通用环境配置实验记录6. 课后作业 视频地址&#xff1a; (2)轻松玩转书生浦语大模型趣味Demo 文档教程&a…

Java电影购票小程序在线选座订票电影

Java电影购票小程序 功能&#xff1a;注册用户可已查看电影场次评价选座订票退票&#xff0c;影院管理员可以排片退款在线卖票和管理演播室等。超级管理员可管理电影排片电影院用户管理等。 演示视频 小程序&#xff1a; https://www.bilibili.com/video/BV11W4y1A7mK/?shar…

2.【CPP】入门(宏||内联函数||拷贝构造||析构函数||构造函数)

0x01.引言 1.实现一个宏函数ADD #define ADD(x,y) ((x)(y))//宏是预编译阶段完成替换&#xff0c;注意括号2.宏的优缺点 优点&#xff1a; 1.增强代码的复用性 2.宏函数不用建立栈帧&#xff0c;提高性能 缺点&#xff1a; 1.不方便调试 2.没有安全检查 0x02.内联函数 1.以空…

一起学习python类的属性装饰器@property

之前文章我们介绍了class的一些通用功能&#xff0c;比如类属性/类方法/实例属性/实例方法等&#xff0c;之前的属性可以直接修改和访问&#xff08;设置私有属性&#xff0c;不能直接访问,可通过对象名._[类名][属性名]的方式访问&#xff09;&#xff0c;没有一些权限的控制逻…

Linux第24步_安装windows下的VisualStudioCode软件

Visual Stuio Code是一个编辑器&#xff0c;简称 为 VSCode&#xff0c;它是微软出的一款免费编辑器。 VSCode有 Windows、 Linux和 macOS三个版本的&#xff0c;是一个跨平台的编辑器。VSCodeUserSetup-x64-1.50.1是Windows系统中的VSCode软件&#xff0c;而“code_1.50.1-160…

大创项目推荐 深度学习手势识别算法实现 - opencv python

文章目录 1 前言2 项目背景3 任务描述4 环境搭配5 项目实现5.1 准备数据5.2 构建网络5.3 开始训练5.4 模型评估 6 识别效果7 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习手势识别算法实现 - opencv python 该项目较为新颖…

212. 单词搜索 II(字典树的另一种类型)

大致思路是&#xff1a; 根据words列表建立字典树&#xff0c;其中注意在单词末尾&#xff0c;将原来的isEnd变量换成存储这个单词的变量&#xff0c;方便存储到ans中&#xff0c;另外&#xff0c;字典树的字节点由原来的Trie数组变为hashmap&#xff0c;方便检索字母。 建立…

React之自定义路由组件

开篇 react router功能很强大&#xff0c;可以根据路径配置对应容器组件。做到组件的局部刷新&#xff0c;接下来我会基于react实现一个简单的路由组件。 代码 自定义路由组件 import {useEffect, useState} from "react"; import React from react // 路由配置 e…

(超详细)4-YOLOV5改进-添加ShuffleAttention注意力机制

1、在yolov5/models下面新建一个SE.py文件&#xff0c;在里面放入下面的代码 代码如下&#xff1a; import numpy as np import torch from torch import nn from torch.nn import init from torch.nn.parameter import Parameterclass ShuffleAttention(nn.Module):def __…

软件测试|使用Python打印五子棋棋盘

简介 五子棋是我们传统的益智类游戏&#xff0c;在制作五子棋时&#xff0c;我们需要先将棋盘打印出来&#xff0c;本文就来介绍一下使用Python打印五子棋棋盘。 步骤一&#xff1a;打印空棋盘 首先&#xff0c;我们需要在Python中定义一个棋盘函数&#xff0c;该函数将打印…

Confluence跨大版本升级记录

初始版本7.4.18最终升级到了目前的最新版本8.7.1&#xff0c;在升级过程中遇到了很多问题&#xff0c;庆幸的是最后都解决了&#xff0c;记录一下。 背景 初始环境&#xff1a; OS&#xff1a;CentOS8.5 DB&#xff1a;10.8.8-MariaDB Confluence&#xff1a;7.4.18 公司…

数据驱动下的LLM优化:如何从数据集中发掘最大价值?

来源&#xff0c;公众号&#xff1a;芝士AI吃鱼 本文聚焦于通过使用精心策划的数据集对LLM进行微调&#xff0c;以提升其建模性能。具体来说&#xff0c;本文强调了涉及修改、使用或操纵数据集进行基于指令的微调的策略&#xff0c;而不是改变模型架构或训练算法。本文还将解释…