从APP的存活状态区分,实现触达有两种方式,一种是:APP非活跃状态时的站外触达,主要包含:短信、Push、桌面小组件等
另一种是:APP活跃状态时的站内触达,主要包含站内弹窗、页面固定运营位,feed流推荐位等。
下面介绍下一下我们实现的几种触达方式及遇到的一些问题。
短信的消息触达能力是毋庸置疑的,虽然短信文本中直接放入的链接我们也可以打开,但是确存在一些局限性,这种方式仅支持打开web页面,无法跳转到APP原生页面,另外点击链接会先弹窗,由用户选择打开链接的app,这种体验相比直接打开APP指定页面来说大打折扣。因此,如何通过短信直接到达APP内
相应的落地页就是我们需要解决的问题。google提供了一种能使Android系统直接通过网站地址打开应用程序对应内容页面,而不需要用户选择使用哪个应用来处理网站地址的方式,即AndroidAppLinks;其工作流程如下:
要添加AndroidAppLinks到应用中,需要在应用里定义通过Http(s)地址打开应用的intentfilter,并验证你确实拥有该应用和该网站。
如果系统成功验证到你拥有该网站,那么系统会直接把URL对应的intent路由到你的应用。
1.在AndroidManifest里配置用于系统进行验证的IntentFilter:
当android:autoVerify="true"出现在你任意一个intentfilter里,在Android6.0及以上的系统上安装应用的时候,会触发系统对APP里和URL有关的每一个域名的验证。验证过程设计以下步骤:
只有当系统为AndroidManifest里找到的每一个域名找到对应的数字资产文件,系统才会把你的应用设置为特定链接的默认处理器。
数字资产示例:
package_name:在build.gradle里定义的applicationID
[{"relation":["delegate_permission/common.handle_all_urls"],"target":{"namespace":"android_app","package_name":"xxx.xxx.xx","sha256_cert_fingerprints":["xx:xx...."]}}]3.跳转落地页
在配置了上述intentfilter的Activity中解析url,并执行跳转落地页等操作
4.问题及排查方法
4.1确认数字资产文件是否被正确地定义和发布:
4.2确认应用是否设置了正确链接处理方式:
adbshellamstart-aandroid.intent.action.VIEW\
-candroid.intent.category.BROWSABLE\
4.3检查链接策略
执行:adbshelldumpsyspackagedomain-preferred-apps或adbshelldumpsyspackaged
该命令返回了设备上每一个应用配置的列表,这个列表标明应用和网站之间的关联
Applinkagesforuser0:
Package:com.android.demo代表应用包名
Domains:play.google.commarket.android.com网站域名,多个网站之间用空格分隔
Status:always:xxxx表示应用在Manifest文件里的配置了android:autoVerify="true"状态为always;后面的xxxx和验证是否成功无关,和系统中应用的配置记录有关;
4.4解决机型兼容性适配问题
解决方案:有问题的机型,使用统一下载页中转,下载页执行唤起APP,APP内处理跳转落地页逻辑。
1.客户端推送方案
Google为Android提供了FCM推送,但是因为网络服务等一些原因其可用性不佳;目前国内各厂商rom也都提供了免费的push推送接入能力,同短信比push由于其免费性极大地节约了触达成本。
同时国内也有一些三方推送服务供应商,我们结合京东金融自身业务特点,为了保障数据的安全性以及推送消息的服务质量,最终采取整合华为,小米,OPPO、ViVO、魅族各厂商推送能力与自建通道相结合的方案。
其中厂商推送特点:token有效期内,用户杀死app可以接收到push消息;自建通道特点:app启动后建立连接,接收push消息,杀死APP后收不到push消息,主要用于使用未适配的厂商设备如三星、努比亚等用户接收push消息。
各厂商在push方案的实现上大体相同(厂商push接入流程,下图以MiPush为例),在使用厂商推送的过程中我们也遇到了很多问题,因此了解了各厂商的特性是制定出良好的触达策略前提。
2.厂商推送遇到的问题
2.1push通知消息是否可以个性化展示
不同厂商如华为、OPPO、vivo、小米、魅族等通知栏样式存在一些不同综合对比如下表:
在通知展示的样式上,综合对比来看华为支持inBox的样式,OPPO小米支持大图样式,可以通过这些特点定制出更有特色的通知展示形式来突出通知主题。
华为inBox样式:Inbox样式将每行内容都当作独立的单行文本去展示。文本内容最多可展示5行,每行内容展示不了时后边自动添加“...”
OPPO小米支持大图样式:这种通知可以将更有吸引力的图片展示给用户
2.2App有很多业务推送通知,用户是否可以指定接收分类消息
随着APP的业务越来越复杂,应用的通知越来越多,给用户造成明显打扰;
用户只能全局屏蔽这个应用的全部通知,不能屏蔽部分,然后留下对自己有用的。
为了解决这个问题,Android8.0开始支持开发者给自己的通知分成若干类,然后允许用户单独屏蔽这个类别的通知。
需要进行Channel分类,添加新Channel(以MiPush为例):
ChannelHelperchannelHelper=newChannelHelper(APP_SECRET);ChannelInfochannelInfo=newChannelInfo.Builder().channelId("id")//必填,通知类别的ID,长度不超过200字符.channelName("name")//必填,通知类别的名称,长度不超过40字符.channelDesc("desc")//可选,通知类别的描述,长度不超过300字符.notifyType(0)//必填,通知的效果类型,仅支持0,即振动、提示音、led灯三种效果都无.soundUrl("sound_url")//可选,通知的自定义铃声uri,格式介绍请参见“4.1自定义铃声”.build();Resultresult=channelHelper.addNewChannel(channelInfo,1)不同的channel在系统设置页通知设置中展示如下:
通过细分push通知的类别,增加通道数量可提高push消息在通知栏里的留存率;
2.3如何指定推送方式或人群
各厂商推送方式支持方式如下:
2.3.1基于ReglD的推送
RegID为是推送SDK为每个设备上的每个app注册推送服务时生成的唯一标示。
当开发者需要给一个或多个具体的设备推送消息时,可以使用基于RegID的推送,将个性化的信息推送给指定的设备。这种方式适用于需要为每个用户订制个性化推送的场景。
2.3.2基于Alias的推送
alias是推送提供的一种个性化设定,开发者可以将用户在应用内的账号或其它用户唯一标识设定为用户设备RegID的别名,在推送中可以直接基于别名进行推送。
别名不仅方便开发者将推送与自有的账号系统进行关联,同时也避免了因需要保存设备RegID与自有帐号的对应关系而额外带来的开发和存储成本。
2.3.3基于标签的推送
对应用下已订阅push的设置了标签的用户进行推送。在推送消息时,开发者可以结合每条消息的内容和目标用户人群,选择所对应的标签,完成请求后,push推送服务会向所有
打上这一标签的用户发送该消息,从而满足定向推送的需求。并且提供标签管理功能。
2.3.4小米通道userAccount:最多可对应20台设备,单账号可登陆多台设备,给一个userAccount推送可同时有20台设备收到消息。
总结:将特定的推送消息通过特定的方式发送给比如不同的客户端版本、不同地域、男女等的用户群体,或者通过给不同的用户群体打不同的标签的方式实现特性消息的推送,以达到更精细推送的目的。
2.4OPPO、ViVO触达成功率低,如何提升
触达数据接入数据看板后,经对比各厂商触达成功率发现OPPO、ViVO的触达率基本在83%~86%而小米华为通道触达成功率基本在94%~98%因此提升OPPO、VIVO通达的触达成功率是我们面临的又一问题
OPPO:经排查发现影响OPPO触达率的主要因素为通知开关的状态:APP仅在通知开关开启的情况下才能收到厂商的Push消息而OPPO、一加通知开关在用户安装后默认关闭,因此收不到Push消息。
解决办法:前期主要是制定引导策略,在合适的时机检测通知开关状态,引导用户主动去设置页开启,后来经调研发现OPPO的ColorOS系统提供了一键开启通知开关的能力,后期使用引导一键开启方案,将OPPO通道的触达率提升到了94%左右;
VIVO:与OPPO不同,VIVO设备安装应用后通知开关是开启的,我们根据数仓提供的数据与厂商反馈的错误码分析,导致VIVO触达偏低主要因素为消息未进行分类而被限额。
vivo用户单应用每日运营消息接收条数上限5条,系统消息无限制。vivo用户单应用接收条数限制以“到达量”是否超过5条为准,在发送时校验单用户是否到达5条,超限则计入管控量。
除VIVO外,华为、OPPO、小米对通知消息的数量都有一定的限制,对于存在限额的厂商通道,将点击率高的个性化推送策略尽量安排在上午推送,可以保证优质推送内容的到达率;通过提高消息推送的额度,提高push消息的触达率。
2.5如何增强未读消息提醒
可以在App桌面角标显示未读消息数,厂商lunchapp和pushsdk对此提供了相应的能力支持,用于增强提醒,各厂商的实现细节上有差异:
华为:角标未读数由服务端下发的push消息控制,开放了api供第三方应用设置角标未读数,移除通知栏消息角标数量不会变化。
小米:角标未读数等于厂商push通道(系统通知栏)收到的该app的未读通知数,开放api供第三方应用设置角标未读数。移除系统通知栏消息,角标数量相应减少。
oppo:支持红点,数字角标,角标未读数等于厂商push通道(系统通知栏)收到的该app的未读通知数。
vivo:桌面角标未读数开关默认关闭,需要用户手动开启才能使用,提供设置角标未读数的能力。
角标适配的问题及解决办法:
2.5.1在小米系统上能展示通知数,但无法更新站内信数量。
解决方案:站内信和push打通,进入app时同步更新未读数。
2.5.2在华为系统上无法显示Push数量,站内信数显示正常。
解决方案:华为推送服务提供了在服务端设置桌面角标API接口,第三方app可以在消息中封装角标参数。
2.5.3vivo手机上不支持显示角标未读数。
解决方案:更新SDK版本,接入角标能力
2.5.4在oppo角标展示仅站内信数量。
push功能在开通时可以申请圆点角标或数字角标、无角标三种形式,用户可以在通知设置中自主选择。
oppopush支持的系统版本,目前支持ColorOS3.1及以上的系统的OPPO的机型,一加5/5t及以上机型,realme所有机型(Android8.0以后的设备)。
2.5.5其他:魅族手机未开放桌面角标设置。
1.站内横幅方案介绍
已有的触达方式对用户实时行为产生的场景覆盖不够,而且这类场景较离线场景相比实时性更高,对用户来说相对更重要。针对这个情况,我们增加了对实时场景覆盖。
站内横幅整体设计概览
数据服务层:各业务模块负责采集用户行为数据,由molo侧将用户行为抽象关系模型,用户进入指定场景,触发对应场景触达策略,再经统一频控量控进行核验
传输层:基于MQTT协议的长链接实现的鹰眼自建通道,将通过核验的触达信号传递给下一流程
APP基础能力层:为触达消息传输,流程监控提供基础能力
数据解析层:将传递过来的触达消息体解析,合法性校验,监控异常数据
视图控制层:进行触达消息模板视图创建,弹出方式识别,通过ViewCore给触达消息视图注入生命周期,出入场动画,声音震动提醒、展示动效等各种定制化属性
2.京东金融App站内横栏应用场景
站内横栏功能上线后,为一批业务提供了有效的触达策略
3.遇到的问题及解决思路
3.1如何让横栏实现在App站内全局
全局弹窗这个实现起来相对容易,主要依赖注册的页面生命周期监听,利用WindowManager在离开页面时移除view,在进入新页面重新添加;
3.2指定页面显示或指定页面不显示问题
指定页面的前提是能区分是哪个页面,分两种情况:
Web页面,首先获取运营在鹰眼平台配置的指定的Web链接,再通过APP的web容器获取当前正在加的web页面的链接地址,两个地址进行匹配,需要注意本地取到的url里参数存在比运营配置多的情况,因此匹配时我们认为只要本地取到的参数包含配置的地址中的各参数即是匹配成功;
原生页面,方式一,路由地址匹配:我们首先取原生页面的路由信息,本地有路由信息根据路由地址去匹配,若原生页面无路由地址,需要进行适配
方式二,popClass匹配:需要将原生页面的类路径录入到后台页面配置表进行维护,匹配时根据页面的类路径进行匹配
3.3如何避免多个横栏消息时丢失问题
同时支持多个横栏,这里需要注意的是横栏信息同步问题,我们在创建横栏的时候给横栏创建了一个属性信息对象,每个横栏属性信息都有唯一的key,将横栏属性缓存起来,并给缓存设置最大阈值,达到阈值时最后一个横栏消失清除缓存信息
AppWidget又称小部件、小插件或微件。它是显示在Launcher上,能在Logo以外提供更多信息的一种特别的设计;它方便用户免于打开App即可直接查看信息和进行简单的交互。
1.创建AppWidget
总的来说分以下几个部分:
1.1定义AppWidgetProvider
1.2设置appWidget的基本属性
AppWidgetProviderInfo定义了widget的基本特性,如应用微件的最小布局尺寸、应用微件的初始布局资源、应用微件的更新频率,以及(可选)在应用微件创建时启动的配置Activity。您可以使用单个元素在XML资源中定义AppWidgetProviderInfo对象,并将其保存在项目的res/xml/文件夹中
1.3绘制widget的布局
AppWidget可以支持的布局如下(由于其底层是基于RemoteViews实现,支持的视图较少):
支持使用的View如下(不支持自定义View):
1.4配置ConfigurationActivity
当应用widget使用配置Activity时,由该Activity负责在配置完成后对app的widget进行初始化
1.4.1获取widgetid
1.4.2执行应用微件配置
1.4.3配置完成后,通过调用getInstance(Context)来获取AppWidgetManager的实例
1.4.4通过调用updateAppWidget(int,RemoteViews)来使用RemoteViews布局更新应用微件
1.4.5.最后,创建返回Intent,为其设置Activity结果,然后结束该Activity
1.4.6设置预览图片
在选择创建appWidget时,展示给用户的描绘应用微件是什么样子的一张图片,未配置时默认展示APPlogo
1.4.7配置Service
请求集合中的特定项目时,RemoteViewsFactory会为集合创建相应项目并将其作为RemoteViews对象返回。要在appWidget中添加集合视图,您必须实现RemoteViewsService和RemoteViewsFactory。
1.4.8设置点击事件
通常使用setOnClickPendingIntent()来设置对象的点击行为-例如,让按钮启动Activity。但是,不允许对各个集合项目中的子视图使用此方法。如果要向集合中的各个项目添加点击行为,应改用setOnClickFillInIntent()。这需要为集合视图设置待定Intent模板,然后通过RemoteViewsFactory在集合中的每个项目上设置填充Intent。
2.常见App的实现
金融APP的实现:
3.小组件实践中的问题
3.1如何裁剪图片圆角
一般在开发过程中使用Glide对图片进行裁剪,这里需要注意小组件里使用Glide与平常略有不同,因为拿不到对应的View视图,AppWidgetTarget更适用于小组件加载图片场景,配合MultiTransformation可简便的实现图片圆角的剪裁
小组件本身是不支持自定义view的,若要实现支持自定义字体,可以通过Canvasdrawtext方式给text设置字体样式,粗细、颜色、背景等属性
3.3处理点击响应延迟问题
通过广播形式PendingIntent.getBroadcast处理点击事件,在部分机型上存在延时,最长约7s;可以使用setOnClickPendingIntent方式代替,需要在app的跳转中心处理对应的事件,如跳转落地页、埋点等