十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

国内移动推送对接实战:Android、iOS与Flutter踩坑指南

国内移动推送对接实战:Android、iOS与Flutter踩坑指南 做了这么多年移动端开发推送这件事几乎是每款App都绕不开的坎。尤其在国内做第三方推送对接Android、iOS、Flutter三个平台都要覆盖个推、极光、厂商通道、统一推送联盟这些方案选来选去很容易就被各种SDK、厂商后台、证书配置搞到头皮发麻。我自己前前后后接了不下七八套推送方案踩过的坑估计能写满一页A4纸。今天这篇就把国内第三方移动推送的对接经验一次性捋清楚从选型思路、平台差异、Flutter侧的统一接入到真实环境里的故障排查尽量把我试过的、踩过的、验证过的东西都交代明白。适合正在做推送选型、准备接入或者已经被推送问题折磨到怀疑人生的移动端开发同学参考。1. 推送接入之前先想清楚这三件事1.1 推送的核心矛盾Android后台限制 vs 用户触达很多人第一次接推送以为就是把SDK集成进去、发条消息就完事了。等真正上线才发现推送问题的复杂程度远超预期。这一切的根源在于Android系统的后台限制策略。国内主流手机厂商对后台进程的管控越来越严格App一旦切到后台系统可能随时杀掉你的推送服务进程。这就导致一个很尴尬的局面App还活着的时候推送好好的一旦用户划掉任务卡片或者放后台久了消息就石沉大海。第三方推送SDK在Android端面临的不是技术问题而是与系统限制的博弈问题。所以现在国内做推送基本都形成了共识单靠第三方推送的长连接通道无法保证到达率必须走厂商系统级推送通道。小米推送、华为推送、OPPO推送、vivo推送这些系统级通道由系统统一调度即使App进程被杀也能把消息送达。这也是为什么和一些资深同行聊推送方案大家都会强调“多通道集成”这个思路。1.2 选型维度和评估指标选推送方案不能只看官网宣传我一般按下面几个维度去评估到达率与送达速度厂商通道的到达率明显优于第三方自建长连接尤其是App被杀后的场景。可以自己做个统计分场景前台、后台、被杀测到达率和延迟。SDK体积与资源占用第三方推送SDK普遍不轻有些SDK加了厂商通道之后包体积、内存占用还能再涨一截。对于包体敏感的产品需要专门关注一下。厂商后台配置复杂度华为、小米、OPPO、vivo各家都有自己的推送平台申请账号、开通服务、配置SHA256指纹、回执配置一环扣一环。如果只接极光或个推的主通道集成就简单很多但到达率会打折。厂商SDK的坑位在不同厂商的机型上厂商SDK本身也是系统自带的所以集成后对系统版本的兼容性、对不同机型的适配情况都各有差异。有些厂商的SDK更新频繁你需要持续跟进。2. 国内主流第三方推送方案逐家梳理2.1 个推 vs 极光老牌推送服务商的差异化个推和极光是国内用得最多的两家第三方推送服务商它们的产品形态越来越像但在细节上还是有区别。个推GeTui的特点是起家较早在Android推送通道上有比较深的技术积累尤其是长连接的稳定性表现不错。它的SDK支持通道合并策略——如果检测到厂商系统推送通道可用会自动优先走厂商通道否则走自己的长连接。这种“自动降级”机制在厂商通道覆盖不全的低版本机型上非常实用。个推后台的消息报表、用户分群、定时推送这些功能也做得比较完善。极光推送JPush在开发者体验方面做得比较好API文档清晰、接入文档完善后台界面也直观。极光有一个很实用的功能是“过期消息”可以设置消息的有效期超过时间未被送达的消息自动丢弃。做活动推送时这个功能能避免用户第二天打开App还被昨晚的促销通知轰炸。极光的Flutter插件更新频率也比较高对跨平台开发友好。这两家在功能层面其实没有绝对高下真正的差异体现在你所在团队的技术栈、服务商客户服务的反馈速度、以及你的核心场景比如对海外推送有需求的话需要关注服务商是否支持海外通道。我在项目里通常会把个推和极光都建一个测试应用用真实业务场景跑一周看数据再作决定。2.2 厂商通道与统一推送联盟的定位变化国内消息推送已经在向“系统级”方向演进最直接的表现就是厂商通道在推送方案中的权重越来越大。我在实际项目中已经把“集成第三方推送集成各厂商通道”作为标配。例如集成极光时同时也需要在极光后台申请小米、华为、OPPO、vivo的开发证书和密钥把它们绑定到极光的厂商通道配置里。这样做的好处是用户手机上的系统推送服务接管了消息分发App进程被清理后依然可以收到通知到达率可以做到95%以上。“统一推送联盟”推出的统一推送标准UPT本质上就是试图把国内混乱的推送生态收敛到一个系统级标准上。它要求各成员厂商在系统侧实现一条统一的推送通道App只需接入一次即可通过系统通道触达用户从而减少App各自建立长连接带来的电量消耗和后台资源占用。在实际落地层面统一推送标准在部分国产机型上已有支持但覆盖范围还在逐步扩大。对于开发者而言短期内仍需以“第三方SDK厂商通道”为主同时关注新的系统级通道标准的变化后续做适配时能更从容。3. Android端接入的完整实操与陷阱排查3.1 厂商通道SDK的接入与配置Android端的推送接入核心就是处理多厂商渠道的注册和消息路由。如果你用的是个推或极光这类第三方SDK它们已经把厂商通道做成了SDK内部的模块你只需在后台配置参数再在代码里引入对应厂商的辅助包即可。以极光接入小米通道为例关键步骤是// build.gradle 中引入小米厂商通道辅助包 implementation cn.jiguang.sdk.plugin:xiaomi:4.6.4然后在小米开放平台申请AppKey、AppID并配置到极光后台对应的渠道中。同一个App需要在多个厂商平台都申请一遍流程大同小异。需要注意的地方是华为推送。华为的SDK从旧版HMS Core转向新版本后需要在华为开发者联盟控制台开通推送服务并且要在项目的agconnect-services.json文件里配置App信息。如果你用的第三方SDK集成了华为厂商通道这个agconnect-services.json文件也要放在App模块的main目录下。我第一次接入华为通道时漏了这个文件结果运行时直接报AGC_APP_NOT_CONFIGURED排查了半天。厂商通道的回执配置也是容易忽略的一环。如果你在厂商后台没有正确配置消息回执地址那么推送到达率报表里就会缺少厂商通道的数据导致你误判为消息没送达。个推和极光的后台都有回执配置说明建议接入时一次性配好后面省不少事。3.2 Android 13通知权限与适配问题从Android 13API 33开始通知权限变成了运行时权限需要在代码里动态申请POST_NOTIFICATIONS权限。这个变化直接影响推送功能的首次配置流程。如果你的App targetSdkVersion已经升到33以上而你没有主动申请通知权限用户在安装App后默认收不到任何通知包括推送消息。这个权限需要引导用户开启否则后续的推送都是白搭。常见的适配代码// Android 13 及以上需要运行时申请通知权限 if (Build.VERSION.SDK_INT 33) { if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) ! PackageManager.PERMISSION_GRANTED) { requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1001) } }千万别只在MainActivity里申请很多App的推送入口是启动就初始化的用户如果首启时拒绝之后再想通过提示弹窗引导就会很麻烦。建议做一层推送权限引导页在用户拒绝后解释“为什么需要通知权限”再引导去系统设置里打开。还有一个小坑是NotificationChannel。从Android 8.0开始通知必须绑定一个Channel才能展示。如果你没创建Channel推送消息会无声无息地消失或者被归入默认分组。第三方SDK一般会创建自己的默认Channel但建议还是自己创建业务Channel这样用户可以单独控制某个类型的通知是否接收体验更精细。3.3 点击通知行为的正确实现推送通知的点击行为是很容易做得粗糙的地方。如果只是一条简单的消息展示点击后打开App主页面就够了。但对于运营类推送通常希望点击后能跳转到具体业务页面比如跳转到订单详情、活动页等。常规做法是在推送payload里带上一个url字段或route字段客户端点击通知后解析这个字段再根据约定好的路由规则做跳转。我见过不少团队直接把跳转逻辑写在Activity的onCreate里通过Intent获取推送参数。这样做的问题是App被杀后通过通知栏点击启动App时是冷启动路径Activity栈是全新的你需要处理“启动后恢复页面栈”的情况和参数传递的时机问题。建议用下面这种方式// 在Launcher Activity中获取通知带来的Intent参数 Intent intent getIntent(); if (intent ! null) { String route intent.getStringExtra(push_route); if (route ! null) { // 延迟到页面初始化完成后再执行跳转 getWindow().getDecorView().post(() - RouterUtils.navigate(route)); } }这里有个细节如果App的进程已经被系统回收点击通知后系统会重新创建进程再启动配置里的Launcher Activity。这时候onCreate里拿到的Intent才是通知携带的Intent你需要确保这个流程能正确处理。4. iOS端接入要点证书、VoIP与前后台策略4.1 证书配置与推送环境隔离iOS端的推送核心是APNsApple Push Notification service第三方SDK在iOS端的作用更多是封装APNs的注册和消息处理它自己没有独立的推送通道。所以iOS端的推送质量很大程度上取决于你APNs层配置得对不对。证书配置是绕不过去的第一道坎。现在APNs的鉴权推荐使用APNs Auth Key.p8文件相比传统的证书.p12可以避免一年一续期的烦恼。你需要在Apple Developer后台生成一个APNs Auth Key然后把它配置到个推或极光的后台让服务端用这个Key向APNs发送推送请求。开发环境和生产环境一定区分开。我踩过一个印象很深的坑开发证书配置成了生产环境的p12结果测试包永远收不到推送。当时的问题是开发模式测试但推送服务端用了生产环境的APNs鉴权。iOS的推送环境是隔离的开发环境sandbox和生产环境production必须严格对应否则消息就是已发送但永远到达不了。如果你使用极光或个推需要在其后台同时配置开发环境和生产环境的推送证书。在模拟器上测试时要注意模拟器在特定系统版本上对APNs的支持也有限制建议直接用真机测。4.2 通知权限申请与点击统计iOS的推送集成相对Android要简单一些因为系统对后台进程有统一管理不存在“杀进程收不到推送”的问题。但需要注意两个细节。第一通知权限的申请时机。iOS会在App启动后弹窗询问是否允许通知用户一旦选择拒绝后续就无法再次弹窗只能引导用户去系统设置中手动打开。所以很多产品倾向于延迟申请权限让用户在充分了解产品价值后再点击允许。但这里有个平衡如果权限申请太晚可能导致用户只听不到重点通知的覆盖影响产品核心功能的使用体验。第二点击统计。iOS的通知点击埋点需要在UNUserNotificationCenterDelegate的回调中手动上报func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, completionHandler: escaping () - Void) { let userInfo response.notification.request.content.userInfo // 上报点击事件到推送服务商后台 JPUSHService.handleRemoteNotification(userInfo) completionHandler() }不要小看这个点击统计。没有正确上报推送后台的转化数据就会不准确运营后续做投放分析时就完全抓瞎。4.3 VoIP推送和其他特殊场景如果你的App有音视频通话等强实时需求常规的APNs推送延迟不够可以考虑VoIP Push。VoIP推送走的是PushKit框架系统会为VoIP推送保持网络连接延迟更低甚至能在App未运行时杀掉进程前唤起App。但这类推送功能如果被滥用极容易导致App被苹果下架因为苹果对VoIP用途有严格限制——只能用于VoIP通话场景。我个人的建议是除非你的产品确实需要实时通话能力否则不要为了降低推送延迟去碰这个功能。普通业务通知用常规APNs就够了。5. Flutter跨端统一推送方案落地5.1 插件选型jpush_flutter vs 个推Flutter插件Flutter项目接入推送常见的有两条路一是使用服务商官方提供的Flutter插件二是自己写MethodChannel桥接原生SDK。服务商官方插件的好处是维护方便、API设计贴合Flutter风格而且底层已处理好了Android厂商通道和iOS APNs的差异。我实际试过jpush_flutter和个推gtpush_flutter两者的API设计都还能接受主要区别还是上面提到的原生SDK能力差异。需要注意Flutter插件版本和原生SDK版本要对应。很多人在升级Flutter版本后发现推送插件编译报错多半是插件版本过旧导致的。接入官方插件后建议在pubspec.yaml里锁定版本号避免自动升级引发不兼容。另外插件自动集成的原生代码默认不会包含厂商通道需要按插件文档手动添加厂商通道的依赖和配置。我在Flutter项目里接入极光后还需要在Android工程中增加小米、华为等厂商通道的辅助包过程与原生Android接入一致。5.2 多端SDK统一封装与消息路由在Flutter项目中建议再做一层业务封装不要让业务代码直接调用推送SDK的API。这样做的原因是如果后续你更换推送服务商比如从极光换到个推只需要替换底层的适配层上层业务代码完全不用动。我的做法是抽象出一个PushService类对外暴露几个统一接口abstract class PushService { Futurevoid init(); FutureString? getToken(); Futurevoid setAlias(String alias); Futurevoid addTags(ListString tags); StreamPushMessage get onMessage; StreamPushMessage get onNotificationClick; Futurevoid stopPush(); }然后分别实现JPushService和GeTuiService在入口处根据后台配置选择实例化哪个实现类。这样封装之后还有一个好处后续如果要加自研发推送通道或者切换成某个厂商的原生通道SDK只需要加一个新的实现类对业务层完全透明。UI层做消息路由时也只用依赖PushMessage中的route字段。5.3 Flutter端常见的编译环境问题Flutter接入推送SDK时最典型的报错就是插件依赖的原生SDK与本地Android构建环境不兼容。比如在Windows上构建Flutter Android项目时常常会遇到unable to find suitable visual studio toolc的报错。这个报错虽然是指向Visual Studio的但本质上是原生代码编译工具链缺失。Flutter插件里凡是包含原生C/C代码的模块在Windows上构建都需要安装Visual Studio的C开发组件。另外fvm在管理Flutter版本时也要注意。如果你的机器上装了多个Flutter版本某个推送插件可能只支持特定范围的Flutter SDK版本用fvm切换版本后跑flutter pub get会重新拉取依赖如果插件不支持当前版本会在编译时报错。建议把项目固定的Flutter版本写进.fvmrc文件团队协作时统一用同一版本构建。还有一种情况是Flutter新版本构建系统变化比如新版Flutter建议用插件默认的Gradle插件方式但旧项目的android/build.gradle还保留老式的apply方式就会出现“you are applying flutters main gradle plugin imperatively using the apply script method”的警告。这个需要按新模板清理掉旧的Gradle配置否则后续打包可能出现奇怪的问题。6. 实战踩坑实录收不到推送的排查路径6.1 8个高频故障的定位顺序对接三方推送时最让人抓狂的就是“后台显示发送成功但用户就是收不到”。下面是我实际排查问题时会按顺序检查的清单你也可以照着这个思路逐项排查。检查项说明处理建议通知权限Android 13 或 iOS 未授权检查系统设置中App通知权限是否开启动态申请或引导开启厂商通道配置是否已申请并配置各厂商密钥华为、小米、OPPO、vivo后台逐一核对AppID、AppKey、Secret是否匹配回执配置厂商通道是否配置消息回执未配置回执会导致推送服务商收不到送达统计无法判断真实状态SDK初始化时机推送SDK是否在App启动早期初始化尽量在Application或main入口最先初始化避免初始化未完成就注册Token进程被杀后通道是否成功注册到厂商系统通道杀掉App进程后用厂商后台手动推送一条测试消息前后台通知策略前台时通知栏展示是否做了特殊处理部分SDK默认前台不展示通知需要检查代码是否设置了忽略前台通知的flag消息类型配置通知消息与透传消息的区别确认发的不是透传消息透传消息默认不展示通知栏手机系统省电策略部分机型对App的电量优化限制引导用户在系统设置中将App设为“不限制后台运行”6.2 推送延迟与到达率的调优手段如果消息最终能收到但延迟明显问题往往出在通道选择或配置上。以Android为例第三方SDK的长连接通道在纯后台状态下会受系统休眠策略影响出现延迟是正常的。要降低延迟就是把厂商通道配好因为厂商通道是系统级服务不受App休眠影响。如果你已经接了厂商通道但延迟依然明显很可能是消息在SDK层被判定走了长连接而非厂商通道。这时需要检查厂商通道设备的注册是否成功。有一种情况容易被忽视同一个用户在不同手机上登录可能会产生多个Token。如果你的服务端没有维护好“用户-设备Token”的映射关系推送可能发到旧Token上。建议客户端在推送Token变化时主动上报给服务端服务端解绑旧设备、绑定新设备。实测下来这一类问题占了“无声丢失”故障中相当高的比例。还有一个提升到达率的细节是离线消息策略。iOS和Android对离线消息的处理逻辑不同iOS会把最后一条离线消息由APNs补发如果系统允许Android的厂商通道一般会缓存有限条数的离线消息超过部分会被丢弃。如果你的消息以活动类为主且时效性要求高可以关闭离线存储避免用户次日打开App收到一堆过期通知。6.3 我的经验和避坑心得推送对接做完不是终点上线后的监控才是重中之重。我建议你在推送SDK的回调里把“上报Token成功”、“收到推送”、“点击推送”这三个事件都接入到自己的数据监控体系。这样即使推送后台数据延迟你也能通过自己的埋点第一时间发现异常。我见过一些团队只依赖推送服务商后台的统计结果服务商后台的报表延迟了几个小时等发现问题时用户已经抱怨很久了。另外多渠道消息合并问题也值得注意。用户可能同时收到厂商通知和第三方SDK的通知导致重复展示。多数第三方SDK已经做了去重逻辑但如果你混合使用多个推送SDK需要自己做好去重标记。我在一个项目里遇到过用户反馈“同样一条消息看到两次”排查下来就是极光的厂商通道和App内自己集成的另一个SDK重复投递导致。最后还有一个小技巧真机测试时不要只在公司WiFi环境下测。蜂窝网络和WiFi的推送行为有时会有差异尤其是Android厂商通道在某些弱网环境下的重连机制表现不同。建议在两种网络环境下都做一轮完整的推送测试覆盖到前台、后台、进程被杀三种场景。推送这个东西表面上看是“调通SDK、发条消息、用户收到”的三步走实际上它背后牵扯的是系统机制、厂商政策、网络环境和业务场景的综合博弈。不同团队的业务模式不同对推送方案的选型也会有不同的结论。但无论选哪家服务商、用哪种通道策略把基础配置做对、把故障排查路径摸透、把数据监控建好这三件事永远是推送到位的基本盘。希望这篇长文能给正在做推送对接的同学一些参考少走几步弯路。
返回列表