此文已由作者熊岑授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
为了让用户与用户间交流自己喜爱的商品,甚至从更大层面来说,让他人知道了解一款电商APP,在社交圈里的分享是很重要的一环,那么电商APP里的分享模块也就显得尤为重要了,是给APP导流的一种方式。随着业务的增多,各种分享的新玩法,那么势必要求分享模块有个清晰的结构和逻辑,便于未来的扩展。
在现在分享组件使用中,面临几个问题:
Native调用分享组件,无法针对不同平台指定不同类型的分享;
分享组件的展示和分享逻辑的调用耦合在一起,代码耦合度太高,如果需要定制额外分享组件的展示,调用逻辑使用起来代价太高;
分享元数据格式混乱,调用者不知道要对哪些字段赋值,不好进行后续的维护与扩展。
针对不同平台定制分享类型,自由支配;
降低分享组件的展示和分享逻辑的耦合度;
提供统一的入口展示分享组件,高内聚。
统计必不可少的内容:分享来源source等;
分享选项:List;ShareOption(包含平台target、名称title、图标资源iconResId);
分享数据:Map;(key为分享平台target、BaseShareData为基础数据类型);
分享基础数据类型:BaseShareData;
a. 标题title
b. 描述desc
c. 普通链接linkUrl
d. 图片地址imageUrl
e. 分享形式style,每个基础数据都指定style可以实现针对不同平台分享不同类型
f. 分享至微信好友、易信好友的文案friendDesc
g. 分享至微信朋友圈、易信朋友圈的文案circleDesc
h. 分享至微信、易信(包含好友和朋友圈)链接的小图标logoUrl
注意:原本f、g、h不应该放在base中,但因为项目中大部分微信和易信分享文案相同,为了不重复写代码所以放在base里。
微信数据类型WeiXinShareData,WeiXinShareData extends BaseShareData,可以更改4中指定的内容,并额外多了一个只针对微信好友、微信朋友圈的字段weixinLink;
二维码数据类型QRShareData,QRShareData extends BaseShareData,同样可以更改4中指定的内容,但真正起作用的是QRShareData自身定义的字段。
举例:一个分享数据一般包含a、b、c、d、e,拿分享到微信的图文链接举例,若定制,可以通过f、g、h定制描述desc、图片地址imageUrl等。在真正进行微信分享时,会对取值做一些兼容方案。
WeixinShare#shareToLink()private void shareLink(final boolean toFriend, final ShareMeta shareMeta, final ShareMeta.BaseShareData shareData) { ...... String url = shareData.linkUrl; String friendDesc = StringUtils.isNotBlank(shareData.friendDesc) ? shareData.friendDesc : shareData.desc; String circleDesc = StringUtils.isNotBlank(shareData.circleDesc) ? shareData.circleDesc : shareData.desc; String imageUrl = StringUtils.isNotBlank(shareData.logoUrl) ? shareData.logoUrl : shareData.imageUrl; if (shareData instanceof ShareMeta.WeiXinShareData) { ShareMeta.WeiXinShareData weiXinShareData = (ShareMeta.WeiXinShareData) shareData; url = StringUtils.isNotBlank(weiXinShareData.weixinLink) ? weiXinShareData.weixinLink : url; } ...... }
UI和逻辑处理的分离,让分享弹窗在UI上的定制更简便。
每个ShareWindow拥有自己的ShareProcessor,提供ShareProcessor#shareFromNative(),通过指定target实现对应平台分享。
ShareProcessor#shareFromNative()只做基础数据的处理部分,比如从分享数据集合中取出对应target的分享内容,获取真正平台的单实例类实现各自平台的逻辑分享。
获取分享平台List;
提供ShareHelper.CreateData抽象类,可以根据需要定制的数据复写抽象类里提供的方法,若需要定制数据,复写的抽象类里的方法返回值不能为null;
提供ShareHelper.SingleCreateData抽象类,可以根据需要定制的数据复写抽象类里提供的方法,若需要定制数据,复写的抽象类里的方法返回值不能为null;比ShareHelper.CreateData多提供ShareHelper.SingleCreateData#createByTarget(int)方法,直接通过target创建对应分享数据;
提供OnTargetClickListener接口,选择拦截具体分享平台的点击,ShareHelper.OnTargetClickListener#onTargetClick()返回值为true表示拦截,false表示不拦截;
主要针对希望先出分享弹窗,再点击到具体平台再生成图片的逻辑而添加。
提供ShareHelper.Builder,展示分享弹窗;
a. ShareHelper.Builder#addData(int, ShareHelper.CreateData)添加定制数据;
b. ShareHelper.Builder#setOptions自定义分享平台集合;
c. ShareHelper.Builder#showShareWindow展示分享弹窗;
提供ShareHelper.SingleBuilder,直接调用指定分享平台分享;
a. ShareHelper.SingleBuilder#addData添加定制数据;
b. ShareHelper.SingleBuilder#shareToTarget直接分享至对应平台;
举例订单详情页分享功能的调用:
通过ShareHelper.Builder添加分享原来和具体的分享内容:具体添加分享内容实现createBase()方法,需要额外定制如定制微博内容则实现createWeibo()方法;
拦截分享到微信朋友圈的操作:因为分享到朋友圈涉及到异步生成图片,为了不延迟分享弹窗的展示,当用户点击分享到微信朋友圈时才生成图片,拿到生成的图片地址后通过ShareHelper.SingleBuilder定制分享样式为分享图片并实现最终的分享到微信朋友圈的逻辑。
new ShareHelper.Builder().addData(ShareConstants.SHARE_WEB, new ShareHelper.CreateData() { @Override public ShareMeta.BaseShareData createBase(ShareMeta.BaseShareData baseShareData) { // 构建基础的分享内容 baseShareData.title = shareView.getShareTitle(); baseShareData.desc = shareView.getShareSubTitle(); baseShareData.imageUrl = shareView.getShareLogo(); baseShareData.linkUrl = shareView.getShareUrl(); baseShareData.style = ShareConstants.STYLE_LINK; return baseShareData; } @Override public ShareMeta.BaseShareData createWeibo(ShareMeta.BaseShareData baseShareData) { // 微博描述可定制 baseShareData.desc = shareView.getShareTitle() + " " + ShareStatisticsHelper.getStatisticsUrl( ShareConstants.TARGET_WEIBO, shareView.getShareUrl()); return baseShareData; } }).setOnTargetClickListener(new ShareHelper.OnTargetClickListener() { @Override public boolean onTargetClick(int target, final ShareMeta.BaseShareData baseShareData) { // 拦截分享到微信朋友圈的操作 if (target == ShareConstants.TARGET_WEIXIN_CIRCLE) { new ShareCouponImgManager().createBigImgCard(OrderDetailActivity.this, (Lifeful) OrderDetailActivity.this, shareView.getShareOrderImageInfoView(), imgName, new ShareCouponImgManager.CreateImgCallback() { @Override public void createSuccess(String shareImgName) { final String imageAbsoluteLocalPath = AdvertiseManager.generateImagePath(imgName); // 生成图片成功后再调用ShareHelper.SingleBuilder指定具体平台的分享 new ShareHelper.SingleBuilder().addData(ShareConstants.SHARE_WEB, target, new ShareHelper.SingleCreateData() { @Override public ShareMeta.BaseShareData createByTarget(int target) { baseShareData.imageUrl = imageAbsoluteLocalPath; baseShareData.style = ShareConstants.STYLE_IMAGE; return baseShareData; } }).shareToTarget(OrderDetailActivity.this, target, true); } @Override public void createFailed() { ToastUtils.show(getString(R.string.share_big_card_fail)); } }); // return true表示拦截处理 return true; } return false; } }).showShareWindow(this, mOrderBottomView);
以上是一个完整的分享流程的调用,当然想要分享出去的的具体平台也是可以定制的,只是没有在此列出。
关于分享模块,感觉对于业务来说还是比较独立的,未来考虑可以抽成独立的Module或者aar引入。
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 代码混淆防止APP被反编译指南
【推荐】 聊一聊数据分析师这个职业