集成说明.md 18 KB

极光推送集成说明

目录结构

capability-push/src/
└── main/
    ├── AndroidManifest.xml          # Android 清单文件(权限声明)
    └── java/
        └── com/narutohuo/xindazhou/push/
            ├── api/                  # API 接口层
            │   └── PushService.kt    # 推送服务接口定义
            ├── factory/              # 工厂类层
            │   └── PushServiceFactory.kt  # 服务工厂(统一入口,单例获取)
            ├── impl/                 # 实现层
            │   └── PushServiceImpl.kt     # 推送服务具体实现(封装极光推送SDK)
            ├── receiver/             # 接收器层
            │   └── JPushReceiver.kt       # 推送消息接收器(完全封装在模块内部)
            ├── mapping/              # 页面映射层
            │   └── ActivityMapping.kt     # 静态页面映射配置(支持应用未启动时跳转)
            └── model/                # 数据模型层
                ├── PushConfig.kt          # 推送服务配置模型
                └── PushResponse.kt         # 推送相关的数据模型
                    ├── PushMessage        # 推送消息模型
                    └── PushResponse       # 推送响应模型

功能说明

1. api/ 层 - 接口定义

  • 职责:定义推送服务的公共接口,业务层只依赖接口
  • 内容PushService 接口,包含初始化、别名/标签设置、消息监听、注册/注销等方法

2. factory/ 层 - 工厂类

  • 职责:提供统一的服务实例获取和初始化方式
  • 内容PushServiceFactory 单例工厂
  • 作用:隐藏实现细节,统一入口,便于替换实现

3. impl/ 层 - 具体实现

  • 职责:实现 PushService 接口的具体逻辑
  • 内容PushServiceImpl 单例实现类
  • 功能:封装极光推送 SDK 调用,处理推送消息接收,错误处理和日志记录

3.1 receiver/ 层 - 消息接收器

  • 职责:封装推送消息接收逻辑
  • 内容JPushReceiver BroadcastReceiver
  • 功能
    • 自动接收极光推送的消息(自定义消息、通知消息、通知点击)
    • 自动解析消息内容
    • 完全封装:在模块的 AndroidManifest.xml 中自动注册,业务层无需处理
    • 自动跳转:优先使用静态配置(ActivityMapping)自动处理通知点击跳转,支持应用未启动场景

3.2 mapping/ 层 - 页面映射配置

  • 职责:提供静态页面映射配置,支持应用未启动时的跳转
  • 内容ActivityMapping 静态配置类
  • 功能
    • 静态配置:页面映射关系在编译时确定,不依赖运行时初始化
    • 应用未启动支持:即使应用从未启动过,点击通知也能正常跳转
    • 向后兼容:支持运行时动态配置(通过 pageMappings 参数)
    • 优先级:静态配置优先,运行时配置作为补充

4. model/ 层 - 数据模型

  • 职责:定义推送相关的数据模型
  • 内容
    • PushConfig - 推送服务配置模型
    • PushMessage - 推送消息模型(标题、内容、扩展数据等)
    • PushResponse - 推送响应模型(成功/失败、错误信息等)

架构设计

  • 接口隔离:业务层只依赖接口,不依赖实现
  • ARouter 依赖注入:通过 ARouter 实现模块间解耦,base-core 定义接口,能力层实现接口
  • 工厂模式:统一入口,隐藏创建逻辑(内部使用 ARouter 获取服务)
  • 单例模式:全局共享一个服务实例
  • 分层架构:base-core (接口) → capability-push (实现) → ARouter (注册) → Factory (获取)
  • 完全封装:跳转逻辑封装在模块内部,外部只需配置页面映射规则
  • 静态配置优先:使用静态配置(ActivityMapping)确保应用未启动时也能正常跳转

ARouter 架构说明

  • base-core 模块定义 IPushService 接口(位于 com.narutohuo.xindazhou.core.push
  • capability-push 模块实现 IPushService 接口,并通过 @Route(path = "/push/service") 注册到 ARouter
  • Factory 内部使用 ARouter.getInstance().navigation(IPushService::class.java) 获取服务实例
  • 业务层 通过 Factory 获取服务,无需直接依赖实现模块

已完成的工作

SDK 依赖已添加

  • jpush-5.9.0.aar - 极光推送SDK(本地 AAR)
  • jcore-5.2.0.aar - 极光推送核心库(本地 AAR)
  • cn.jiguang.sdk.plugin:xiaomi:5.9.0 - 小米通道
  • cn.jiguang.sdk.plugin:huawei:5.9.0 - 华为通道
  • cn.jiguang.sdk.plugin:oppo:5.9.0 - OPPO通道
  • cn.jiguang.sdk.plugin:vivo:5.9.0 - vivo通道
  • cn.jiguang.sdk.plugin:meizu:5.9.0 - 魅族通道

代码实现已完成

  • PushServiceImpl 已实现极光推送 SDK 调用,并实现 IPushService 接口
  • PushServiceImpl 已通过 ARouter 注册(@Route(path = "/push/service")
  • PushServiceFactory 已创建,内部使用 ARouter 获取服务
  • IPushService 接口已在 base-core 模块定义
  • PushConfig 配置模型已创建
  • JPushReceiver 消息接收器已封装
  • ActivityMapping 静态页面映射已实现:支持应用未启动时的跳转
  • 跳转逻辑已封装:自动跳转功能已实现,优先使用静态配置
  • ARouter 集成完成:模块间解耦,通过 ARouter 进行依赖注入

配置已完成

  • 所有配置都在 capability-push 模块中管理
  • AndroidManifest.xml 已在 capability-push/src/main/AndroidManifest.xml 中配置
  • strings.xml 已在 capability-push/src/main/res/values/strings.xml 中配置

需要您配置的内容

1. 在极光推送官网注册应用

  1. 访问 极光推送官网
  2. 注册账号并创建应用
  3. 获取 AppKeyAppSecret

2. 配置厂商通道参数(可选,但推荐)

在各厂商开放平台申请参数,并在 capability-push/src/main/res/values/strings.xml 中配置。

详细步骤请参考厂商通道接入说明.md

3. 配置资源文件

所有配置都在 capability-push/src/main/res/values/strings.xml 中管理

编辑 capability-push/src/main/res/values/strings.xml

<resources>
    <!-- 极光推送基础配置(必填) -->
    <string name="jpush_app_key">您的极光推送 AppKey</string>
    <string name="push_jpush_channel">developer-default</string>
    
    <!-- 厂商通道配置(可选,但推荐配置以提升推送到达率) -->
    <!-- 详细配置请参考 厂商通道接入说明.md -->
</resources>

3.5 配置静态页面映射(推荐,支持应用未启动场景)

方式1:使用静态配置(推荐)

capability-push/src/main/java/com/narutohuo/xindazhou/push/mapping/ActivityMapping.kt 中配置:

package com.narutohuo.xindazhou.push.mapping

import com.narutohuo.xindazhou.core.log.ILog

/**
 * 静态页面映射配置
 * 
 * 优势:
 * - 支持应用未启动时的跳转
 * - 不依赖 Application.onCreate() 的执行顺序
 * - 更可靠,避免初始化时序问题
 */
object ActivityMapping {
    /**
     * 静态页面映射配置
     * 页面名称 -> Activity 完整类名
     */
    private val pageToActivityMap = mapOf(
        "detail" to "com.narutohuo.xindazhou.ui.DetailActivity",
        "home" to "com.narutohuo.xindazhou.ui.MainActivity",
        "order" to "com.narutohuo.xindazhou.ui.OrderActivity",
        // 添加更多页面映射...
    )
    
    /**
     * 根据页面名称获取 Activity Class
     * 
     * @param page 页面名称(从推送的 extras["page"] 获取)
     * @return Activity Class,如果未找到返回 null
     */
    fun getActivityClass(page: String): Class<*>? {
        val className = pageToActivityMap[page] ?: return null
        return try {
            Class.forName(className)
        } catch (e: ClassNotFoundException) {
            ILog.e("ActivityMapping", "找不到 Activity: $className", e)
            null
        }
    }
}

方式2:使用运行时配置(向后兼容)

Application.onCreate() 中通过 pageMappings 参数配置(见下方"4. 在 Application 中初始化")。

推荐使用方式1(静态配置),因为:

  • ✅ 支持应用未启动时的跳转
  • ✅ 不依赖初始化顺序
  • ✅ 更可靠

4. 在 Application 中初始化(统一入口)

在您的 XinDaZhouApplication 类中初始化推送服务:

// app/src/main/java/com/narutohuo/xindazhou/XinDaZhouApplication.kt
package com.narutohuo.xindazhou

import android.app.Application
import com.narutohuo.xindazhou.push.factory.PushServiceFactory

class XinDaZhouApplication : Application() {
    
    override fun onCreate() {
        super.onCreate()
        
        // ========== 初始化推送服务(从资源文件读取配置)==========
        // 方式1:只使用静态配置(推荐,已在 ActivityMapping 中配置)
        PushServiceFactory.init(
            context = this
        )
        
        // 方式2:同时配置运行时映射(可选,作为静态配置的补充)
        PushServiceFactory.init(
            context = this,
            // 页面映射规则(用于自动跳转,作为静态配置的补充)
            // 注意:如果已在 ActivityMapping 中配置,这里可以不传
            pageMappings = mapOf(
                "detail" to DetailActivity::class.java,  // 详情页
                "home" to MainActivity::class.java,       // 首页
            )
        )
    }
}

配置说明

  • 静态配置优先ActivityMapping 中的配置优先级最高,即使应用未启动也能使用
  • 运行时配置补充pageMappings 参数作为补充,用于动态配置或覆盖静态配置
  • 向后兼容:如果只使用 pageMappings,也能正常工作(但应用未启动时可能失败)

优势

  • 最简单:只需一行代码,配置都在资源文件和静态配置类中
  • 统一入口:通过 PushServiceFactory.init() 统一初始化
  • 跳转逻辑封装:跳转逻辑完全封装在模块内部,外部只需要配置页面映射规则
  • 应用未启动支持:静态配置确保即使应用从未启动过,点击通知也能正常跳转
  • 容错处理:初始化失败不会影响应用启动,只记录日志
  • 自动识别设备:极光推送 SDK 自动识别设备类型并选择对应厂商通道
  • ✅ 业务层不直接依赖极光推送API
  • ✅ 如果更换SDK,只需修改实现层,业务层无需改动

核心功能说明

1. 通知展示(系统通知栏)

不需要我们处理,系统自动显示

  • 极光推送 SDK 会自动在系统通知栏显示通知
  • 系统会自动处理通知的展示、图标、声音等

2. 通知点击跳转(已封装)

跳转逻辑已完全封装在模块内部!

工作原理

  1. 用户点击通知栏通知
  2. 模块内部自动解析 extras["page"]
  3. 优先使用静态配置:从 ActivityMapping 获取 Activity Class(支持应用未启动场景)
  4. 备选方案:如果静态配置未找到,使用运行时配置的 pageMappings
  5. 根据映射关系自动跳转到对应 Activity
  6. 所有 extras 参数自动传递给目标 Activity

优势

  • 应用未启动支持:即使应用从未启动过,点击通知也能正常跳转
  • 不依赖初始化顺序:静态配置在类加载时即可用,不依赖 Application.onCreate()
  • 更可靠:避免因初始化时序问题导致的跳转失败
  • 向后兼容:仍支持运行时动态配置 pageMappings

服务器推送格式

{
  "notification": {
    "title": "新订单",
    "alert": "您有一个新订单待处理"
  },
  "extras": {
    "page": "detail",  // 必须匹配 ActivityMapping 或 pageMappings 中的 key
    "id": "12345"      // 会自动传递给目标 Activity
  }
}

3. 厂商通道(自动识别)

极光推送 SDK 会自动识别设备类型,无需手动处理!

  • 自动识别:SDK 会自动检测设备品牌(小米、华为、OPPO、vivo、魅族等)
  • 自动选择通道:根据设备类型自动选择对应的厂商通道
  • 自动降级:如果设备不是厂商手机,自动降级到极光通道
  • 无需手动处理:不需要判断手机品牌,不需要手动选择通道

使用示例

初始化(在 Application 中)

// 方式1:只使用静态配置(推荐,支持应用未启动场景)
// 页面映射已在 ActivityMapping 中配置
PushServiceFactory.init(
    context = this
)

// 方式2:同时配置运行时映射(可选,作为静态配置的补充)
PushServiceFactory.init(
    context = this,
    messageListener = { message ->
        // 处理自定义消息(透传消息)
        Timber.d("收到推送: ${message.title} - ${message.content}")
    },
    notificationClickListener = { message ->
        // 处理通知点击事件(可选,用于统计、埋点等)
        Timber.d("用户点击通知,已自动跳转")
    },
    pageMappings = mapOf(
        "detail" to DetailActivity::class.java,
        // 注意:如果已在 ActivityMapping 中配置,这里可以不传
    )
)

配置静态页面映射(在 ActivityMapping.kt 中)

// capability-push/src/main/java/com/narutohuo/xindazhou/push/mapping/ActivityMapping.kt
package com.narutohuo.xindazhou.push.mapping

import com.narutohuo.xindazhou.core.log.ILog

object ActivityMapping {
    private val pageToActivityMap = mapOf(
        "detail" to "com.narutohuo.xindazhou.ui.DetailActivity",
        "home" to "com.narutohuo.xindazhou.ui.MainActivity",
        "order" to "com.narutohuo.xindazhou.ui.OrderActivity",
        // 添加更多页面映射...
    )
    
    fun getActivityClass(page: String): Class<*>? {
        val className = pageToActivityMap[page] ?: return null
        return try {
            Class.forName(className)
        } catch (e: ClassNotFoundException) {
            ILog.e("ActivityMapping", "找不到 Activity: $className", e)
            null
        }
    }
}

后续使用(可选,按需调用)

val pushService = PushServiceFactory.getInstance()
pushService.setAlias("user123")  // 设置别名(可选)
pushService.setTags(listOf("vip", "premium"))  // 设置标签(可选)
val registrationId = pushService.getRegistrationId()  // 获取注册ID(可选)
val isEnabled = pushService.isPushEnabled()  // 检查推送状态(可选)

推送消息类型说明

  1. 自定义消息(透传消息)messageListener

    • 不会显示在系统通知栏
    • 需要在应用内自己处理并显示
    • 适用于需要应用内自定义显示的推送
  2. 通知消息(系统通知栏)

    • 展示:由极光推送 SDK 和系统自动处理,自动显示在通知栏
    • 点击:优先使用静态配置(ActivityMapping)自动跳转,支持应用未启动场景(已封装)
    • 适用于需要系统通知栏显示的推送

配置位置说明

⚠️ 重要:所有配置都在 capability-push 模块中管理,app 模块不需要任何配置!

  • 配置位置capability-push/src/main/res/values/strings.xml
  • 清单文件capability-push/src/main/AndroidManifest.xml
  • app 模块:只需要在 Application 中调用 PushServiceFactory.init() 即可

❌ 禁止在 app 模块中配置:

  • 禁止app/src/main/AndroidManifest.xml 中配置极光推送的 meta-data
  • 禁止app/src/main/res/values/strings.xml 中配置极光推送参数
  • 禁止app/build.gradle 中配置极光推送相关参数
  • 所有配置都在 capability-push 模块中!

常见问题

Q1: 应用从未启动过,点击通知能正常跳转吗?

A: 可以! 使用静态配置(ActivityMapping)后,即使应用从未启动过,点击通知也能正常跳转。

原理

  • BroadcastReceiver 是独立组件,系统会在应用未启动时启动应用进程
  • 静态配置在类加载时即可用,不依赖 Application.onCreate() 的执行
  • 跳转逻辑优先使用静态配置,确保可靠性

Q2: 静态配置和运行时配置(pageMappings)有什么区别?

A:

  • 静态配置ActivityMapping):

    • ✅ 支持应用未启动时的跳转
    • ✅ 不依赖初始化顺序
    • ✅ 更可靠
    • ❌ 需要修改代码并重新编译
  • 运行时配置pageMappings):

    • ✅ 可以动态配置
    • ✅ 不需要重新编译
    • ❌ 依赖 Application.onCreate() 的执行
    • ❌ 应用未启动时可能失败

推荐:优先使用静态配置,运行时配置作为补充。

Q3: 如何添加新的页面映射?

A:ActivityMapping.ktpageToActivityMap 中添加新的映射关系:

private val pageToActivityMap = mapOf(
    "detail" to "com.narutohuo.xindazhou.ui.DetailActivity",
    "newPage" to "com.narutohuo.xindazhou.ui.NewPageActivity",  // 新增
)

注意:Activity 类名必须是完整的包名路径。

Q4: 如果静态配置和运行时配置都配置了同一个页面,会使用哪个?

A: 静态配置(ActivityMapping)优先级更高。如果静态配置中找到了对应的 Activity,会优先使用静态配置;如果静态配置中未找到,才会使用运行时配置(pageMappings)。

参考文档