IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android 集成 firebase 推送 -> 正文阅读

[移动开发]android 集成 firebase 推送

1、集成sdk

project

 classpath 'com.google.gms:google-services:4.3.10'
 classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.0'

app

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
    id 'kotlin-kapt'
    id 'com.google.gms.google-services'
    id 'com.google.firebase.crashlytics'
}
    implementation platform('com.google.firebase:firebase-bom:29.0.0')
    implementation 'com.google.firebase:firebase-analytics-ktx'
    implementation 'com.google.firebase:firebase-crashlytics'
    implementation 'com.google.firebase:firebase-messaging'

在android{}里面配置,防止编译不过

 gradle.taskGraph.whenReady {
        tasks.each { task ->
            if (task.name.contains("uploadCrashlyticsMappingFile")) {
                task.enabled = false
            }
        }
    }

把xxx.json放到app目录下面,至此配置结束

2.在manifest.xml中配置,

MyFirebaseMessagingService用来获取推送过来的消息,以及token变化时,把token传给自家的后端

        <service
            android:name=".base.MyFirebaseMessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/bc_app_logo" />
        <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
             notification message. See README(https://goo.gl/6BKBk7) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/font_green" />

**

3.MyFirebaseMessagingService:

**


/**
 * @des
 * @date 2022/3/7
 * @author sam
 */
class MyFirebaseMessagingService : FirebaseMessagingService() {
    private val PUSH_CHANNEL_ID = "ID"
    private val PUSH_CHANNEL_NAME = "peacock"
    private val mNotificationId = 1000
    private var mNotificationManager: NotificationManager? = null
    override fun onCreate() {
        super.onCreate()
        mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                PUSH_CHANNEL_ID,
                PUSH_CHANNEL_NAME,
                NotificationManager.IMPORTANCE_HIGH
            )
            if (mNotificationManager != null) {
                mNotificationManager!!.createNotificationChannel(channel)
            }
        }
    }

    override fun onMessageReceived(p0: RemoteMessage) {
        super.onMessageReceived(p0)
        p0.notification?.body?.apply {
            if (!isRunBackground(applicationContext)) {
                sendNotification(p0.notification!!.body!!, p0)
            }
        }
    }

    override fun onNewToken(p0: String) {
        super.onNewToken(p0)
        Log.e("token changed--->",p0)
        subToken(p0)
    }
   /**
     * 在前台时,点击时的跳转逻辑,及推送通知
     */
    private fun sendNotification(messageBody: String, remoteMessage: RemoteMessage) {
        val intent: Intent
        if (remoteMessage.data.isNotEmpty() && remoteMessage.data["type"] != null && remoteMessage.data["orderId"] != null) {
            //提现
            if (remoteMessage.data["type"] == "1") {
                intent = Intent(this, OrderDetailActivity::class.java)
                intent.putExtra("isShowOnly", false)
                intent.putExtra("orderId", remoteMessage.data["orderId"]!!.toInt())
            }
            //还款
            else if (remoteMessage.data["type"] == "2") {
                intent = Intent(this, RepaymentDetailActivity::class.java)
                intent.putExtra("orderId", remoteMessage.data["orderId"]!!.toInt())
            } else {
                Log.w("-->", "nothing")
                intent = Intent(this, SplashActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
            }
        } else {
            intent = Intent(this, SplashActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        }
        val pendingIntent = PendingIntent.getActivity(
            this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT
        )
        val defaultSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder: NotificationCompat.Builder =
            NotificationCompat.Builder(this, PUSH_CHANNEL_ID)
                .setSmallIcon(R.drawable.bc_app_logo)
                .setContentTitle(remoteMessage.notification?.title ?: "")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent)
        mNotificationManager?.notify(mNotificationId, notificationBuilder.build())
    }


    /**
     * 判断是在前台还是后台
     */
  private  fun isRunBackground(context: Context): Boolean {
        val activityManager = context.applicationContext
            .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val packageName = context.applicationContext.packageName

        val appProcesses = activityManager
            .runningAppProcesses ?: return true
        for (appProcess in appProcesses) {
            if (appProcess.processName == packageName && appProcess.importance ==
                ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
            ) {
                return false
            }
        }
        return true
    }

    /**
     * 发送token到服务器
     */
    private fun subToken(token: String) {
        OkGo.post<String>(Constant.URL_FIRE_BASE_TOKEN)
            .headers(getHeaders(applicationContext))
            .params("token", token)
            .execute(object : GsonCallBack<BaseResponse<Any>>() {
                override fun onSuccess(response: BaseResponse<Any>) {
                    if (response.isSuccess()) {

                    }
                }

                override fun onFail(response: Response<String>?, e: JsonParseException?) {

                }
            })
    }
}

**

4.token删除及重新获取,这个地方是我自己的理解

**
我在退出登录的时候调用了deleteToken
在MainActivity里面调用了getToken,这样可以保证,MyFirebaseMessagingService 里面的onNewToken,当重新登录时候获取到

详细是这样的:

 MainActivity的onCreate里面:
 
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.e("TAG", "Fetching FCM registration token failed", task.exception)
                return@OnCompleteListener
            }

            // Get new FCM registration token
            val token = task.result


            // Log and toast
        })

退出的时候:

  R.id.tv_mine_exit -> {
                SPUtils.getInstance().clear()
                SPUtils.getInstance().putBooleanValue(SPUtils.IS_FIRST_RUN, false)
                FirebaseMessaging.getInstance().deleteToken()
                //清空后再存储
                activity?.finish()
                //false
                LoginActivity.start(activity as AppCompatActivity, false)
            }

**

5.踩坑,重要

**
firebase当app前台的时候并不会显示通知,划线:不显示通知,这个害我郁闷好几天,咋收不到消息哩,,,有个逻辑需要自己处理:
1.当app在后台时,firebase消息展示通知栏,点击默认进Splash,这个没问题
2.当app在前台显示时,firebase不展示通知,需要自己处理逻辑

**

6.权限

**
目前至少国内手机默认不会给通知权限,需要自己写代码引导用户操作
具体代码如下:

调用方式:(dialog自己整)

  if (!isNotifyEnabled(applicationContext)) {
            StarDialog(this).setTitle("notice").setContent("开通知").setConfirmText("确定")
                .setOnStarDialogClickListener(object : StarDialogClickListener {
                    override fun onCancel() {

                    }

                    override fun onConfirm() {
                        startSetting(this@MainActivity)
                    }

                }).show()
        }

import android.app.AppOpsManager
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.annotation.RequiresApi

/**
 * @des 通知工具
 * @date 2022/3/8
 * @author sam
 */

private const val CHECK_OP_NO_THROW = "checkOpNoThrow"
private const val OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"

//调用该方法获取是否开启通知栏权限
fun isNotifyEnabled(context: Context): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        isEnableV26(context)
    } else {
        isEnabledV19(context)
    }
}

/**
 * 8.0以下判断
 *
 * @param context api19  4.4及以上判断
 * @return
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private fun isEnabledV19(context: Context): Boolean {
    val mAppOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
    val appInfo = context.applicationInfo
    val pkg = context.applicationContext.packageName
    val uid = appInfo.uid
    var appOpsClass: Class<*>? = null
    try {
        appOpsClass = Class.forName(AppOpsManager::class.java.name)
        val checkOpNoThrowMethod = appOpsClass.getMethod(
            CHECK_OP_NO_THROW,
            Integer.TYPE, Integer.TYPE, String::class.java
        )
        val opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION)
        val value = opPostNotificationValue[Int::class.java] as Int
        return checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) as Int ==
                AppOpsManager.MODE_ALLOWED
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return false
}


/**
 * 8.0及以上通知权限判断
 *
 * @param context
 * @return
 */
private fun isEnableV26(context: Context): Boolean {
    val appInfo = context.applicationInfo
    val pkg = context.applicationContext.packageName
    val uid = appInfo.uid
    return try {
        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val sServiceField = notificationManager.javaClass.getDeclaredMethod("getService")
        sServiceField.isAccessible = true
        val sService = sServiceField.invoke(notificationManager)
        val method = sService.javaClass.getDeclaredMethod(
            "areNotificationsEnabledForPackage",
            String::class.java,
            Integer.TYPE
        )
        method.isAccessible = true
        method.invoke(sService, pkg, uid) as Boolean
    } catch (e: Exception) {
        true
    }
}

fun startSetting(context: Context) {
    val localIntent = Intent()
    //直接跳转到应用通知设置的代码:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //8.0及以上
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        localIntent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
        localIntent.data = Uri.fromParts("package", context.packageName, null)
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.0以上到8.0以下
        localIntent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
        localIntent.putExtra("app_package", context.packageName)
        localIntent.putExtra("app_uid", context.applicationInfo.uid)
    } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { //4.4
        localIntent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
        localIntent.addCategory(Intent.CATEGORY_DEFAULT)
        localIntent.data = Uri.parse("package:" + context.packageName)
    } else {
        //4.4以下没有从app跳转到应用通知设置页面的Action,可考虑跳转到应用详情页面,
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        if (Build.VERSION.SDK_INT >= 9) {
            localIntent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
            localIntent.data = Uri.fromParts("package", context.packageName, null)
        } else if (Build.VERSION.SDK_INT <= 8) {
            localIntent.action = Intent.ACTION_VIEW
            localIntent.setClassName(
                "com.android.settings",
                "com.android.setting.InstalledAppDetails"
            )
            localIntent.putExtra("com.android.settings.ApplicationPkgName", context.packageName)
        }
    }
    context.startActivity(localIntent)
}

**

补充:

**
我这边推送的后端格式大概是这样的:这里的token是我传给后端的

String registrationToken = "d1OjZra6RSqJcIhsu7bpA9:APA91bHb2oety9CW3R5kYDQjOfkd3HiOhYiW5tdoQrw2jxgMIrw6wGvD9utHbypGWi1uIpy9qTxc55KlI5acZTtoOs6a_mYUapOiLGSoiB8";
        Message message = Message.builder()
                .setNotification(Notification.builder()
                        .setTitle("xxxxx")
                        .setBody("xxxxxxxx")
                        .build())
                //携带数据
                .putData("type", "1")
                .putData("orderId", "285")
                .setToken(registrationToken)
                .build();

        String response = FirebaseMessaging.getInstance().send(message);

不用谢……

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:41:04  更:2022-03-12 17:42:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:30:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码