JS 实现 分享功能逻辑

背景:最近公司在搞一个简易的分享到国外app的功能。起点涉及PC端浏览器,移动端浏览器(ios\aos)、移动端app。跳转时需要检测是否安装了应用,安装了之后直接跳转(不需要跳转到应用拉起分享页,进到应用就可以了),没有安装跳转到下载页面(后面因为技术原因改成不跳转下载页面,而是拉起动画)。

起点,拉起的自定义分享页productShare.html中,放一个按钮示例,其他按钮就不写上了

       <div class="productShareItem" ng-click="goShareFor('facebook','#unInstall1')">
                <div >
                    <img style="width: 67px;height: 50px" class="float-l" src="./images/facebook.png" />
                    <button id="unInstall1"  type="button" class="btn btn-primary btn-cancel productShareUnInstall">未安装应用</button>
                </div>
            </div>

whatsapp

文档

https://faq.whatsapp.com/425247423114725/?locale=zh_CN&cms_platform=iphone

line

文档:里面提到line://已经弃用

https://developers.line.biz/en/docs/messaging-api/using-line-url-scheme/

跳转功能,首先要解决URL Scheme,就是B - app设置好的跳转协议,A-app或者A-浏览器可以通过location跳到被跳转的B-app。但是记得注意一下app内过滤的协议,因为我不是安卓ios工程师,所以一开始点击faceBook的时候无法跳转,后面才知道需要app那边设置一些过滤协议。

    $scope.goShare = function () {
        SwalService.open('productShare.html', $scope, {
            allowOutsideClick: false
        });
    }

    $scope.goShareFor = function (type,unInstall_id) {
        let shareUrl = "";
        let failUrl = "";
        if (isMobile){ //mobile
            if (unInstall_id != undefined && !isAppIn()){
                setTimeout(function () {
                    $(unInstall_id).css({'margin-top':'65px'});
                    $(unInstall_id).css({'visibility': 'visible'});
                    $(unInstall_id).animate({marginTop:'5px'},500);
                    setTimeout(function () {
                        $(unInstall_id).css({'visibility': 'hidden'});
                    }, 500)
                }, 1000)
            }
            switch (type) {
                case"facebook":
                    $scope.copyLink();
                    shareUrl ="fb://";
                    failUrl = "https://apps.apple.com/us/app/facebook/id284882215";
                    if ($scope.isIosIn()){
                        $scope.checkShareUrlForIos(shareUrl,failUrl);
                    }else {
                        $scope.checkShareUrlForAos(shareUrl,failUrl);

                    }
                    break
                case"whatsapp":
                    $scope.copyLink();
                    shareUrl ="whatsapp://";
                    failUrl = "https://apps.apple.com/us/app/whatsapp-messenger/id310633997";
                    if ($scope.isIosIn()){
                        $scope.checkShareUrlForIos(shareUrl,failUrl);
                    }else {
                        $scope.checkShareUrlForAos(shareUrl,failUrl);

                    }
                    break
                case"wechat":
                    $scope.copyLink();
                    shareUrl = "weixin://"
                    if ($scope.isIosIn()){
                        failUrl = "https://apps.apple.com/us/app/wechat/id414478124";
                        $scope.checkShareUrlForIos(shareUrl,failUrl);
                    }else {
                        failUrl = "https://sj.qq.com/appdetail/com.tencent.mm";
                        $scope.checkShareUrlForAos(shareUrl,failUrl);

                    }
                    break
                case"line":
                    // https://line.me/R/msg/text/?(url)
                    $scope.copyLink();
                    shareUrl ="https://line.me/R/";
                    //如果用户安装了LINE,则当用户使用LINEURL方案访问URL时,将自动启动应用程序,
                    // 并将用户重定向到指定内容。如果用户未安装LINE,则行为取决于LINEURL方案的格式

                    failUrl = "https://apps.apple.com/us/app/line/id443904275";
                    if ($scope.isIosIn()){
                        $scope.checkShareUrlForIos(shareUrl,failUrl);
                    }else {
                        $scope.checkShareUrlForAos(shareUrl,failUrl);

                    }
                    break
                case"messager":
                    $scope.copyLink();
                    shareUrl = "fb-messenger://"
                    failUrl = "https://apps.apple.com/us/app/messenger/id454638411";
                    if ($scope.isIosIn()){
                        $scope.checkShareUrlForIos(shareUrl,failUrl);
                    }else {
                        $scope.checkShareUrlForAos(shareUrl,failUrl);

                    }
                    break
                case"email":
                    $scope.copyLink();
                    $scope.ShareEmail();
                    return;
                    break
                case"copyLink":
                    $scope.copyLink();
                    $('#copSucc2').css({'margin-top':'65px'});
                    $("#copSucc2").animate({marginTop:'5px'},500);
                    $scope.showCopySuccess = true;
                    $timeout(function () {
                        $scope.showCopySuccess = false;
                    },500);
                    return;
                    break
            }
        }else { //web
            switch (type) {
                case"facebook":
                    $scope.copyLink();
                    shareUrl ="fb://";
                    failUrl = "https://www.facebook.com";
                    $scope.checkShareUrlForWeb(shareUrl,failUrl);
                    break
                case"whatsapp":
                    $scope.copyLink();
                    shareUrl = "whatsapp://";
                    failUrl = "https://wa.whagsuwso.cc/whatsapp";
                    $scope.checkShareUrlForWeb(shareUrl,failUrl);
                    break
                case"wechat":
                    $scope.copyLink();
                    shareUrl = "weixin://"
                    failUrl = "https://wx.qq.com/";
                    $scope.checkShareUrlForWeb(shareUrl,failUrl);
                    break
                case"line":
                    // https://line.me/R/msg/text/?(url)
                    $scope.copyLink();
                    shareUrl = "line://"
                    failUrl = "https://access.line.me/oauth2/v2.1/login?returnUri=%2Foauth2%2Fv2.1%2Fauthorize%2Fconsent%3Fscope%3Dopenid%2Bprofile%2Bfriends%2Bgroups%2Btimeline.post%2Bmessage.write%26response_type%3Dcode%26redirect_uri%3Dhttps%253A%252F%252Fsocial-plugins.line.me%252Fwidget%252FloginCallback%253FreturnUrl%253Dhttps%25253A%25252F%25252Fsocial-plugins.line.me%25252Fwidget%25252Fclose%26state%3D9fec98665820574ebc349f47d089a6%26client_id%3D1446101138&loginChannelId=1446101138#/";
                    $scope.checkShareUrlForWeb(shareUrl,failUrl);
                    break
                case"messager":
                    $scope.copyLink();
                    shareUrl = "messenger://"
                    failUrl = "https://www.facebook.com/messages";
                    $scope.checkShareUrlForWeb(shareUrl,failUrl);
                    break
                case"email":
                    $scope.copyLink();
                    $scope.ShareEmail();
                    return;
                    break
                case"copyLink":
                    $scope.copyLink();
                    $('#copSucc2').css({'margin-top':'65px'});
                    $("#copSucc2").animate({marginTop:'5px'},500);
                    $scope.showCopySuccess = true;
                    $timeout(function () {
                        $scope.showCopySuccess = false;
                    },500);
                    return;
                    break
            }
        }
    }

    $scope.checkShareUrlForAos = function (shareUrl,failUrl) {
        var timeout, t = 1000, hasApp = true;
        setTimeout(function () {
            if (hasApp) {
            } else {
                // window.location = failUrl;
            }
            document.body.removeChild(ifr);
        }, 2000)

        var t1 = Date.now();
        var ifr = document.createElement("iframe");
        ifr.setAttribute('src', shareUrl);
        ifr.setAttribute('style', 'display:none');
        document.body.appendChild(ifr);
        timeout = setTimeout(function () {
            var t2 = Date.now();
            if (!t1 || t2 - t1 < t + 100) {
                hasApp = false;
            }
        }, t);
    }
    $scope.checkShareUrlForIos = function (shareUrl,failUrl) {
        var timeout, t = 1000, hasApp = true;
        setTimeout(function () {
            if (hasApp) {
            } else {
                // window.location = failUrl;
            }
        }, 2000)

        var t1 = Date.now();
        window.location = shareUrl;
        timeout = setTimeout(function () {
            var t2 = Date.now();
            if (!t1 || t2 - t1 < t + 100) {
                hasApp = false;
            }
        }, t);
    }
    $scope.checkShareUrlForWeb = function (shareUrl,failUrl) {
        $scope.callapp_PC(shareUrl,failUrl);
    }

    $scope.callapp_PC = function (url, failUrl) {
        var t = setTimeout(function(){
            window.open(failUrl);
        }, 1000);
        var inp = document.createElement("input");
        inp.style.position = "absolute";
        inp.style.clip = "rect(0, 0, 0, 0)";
        // 出现下载框的时候往下跳的问题
        inp.style.top = '0'
        inp.style.left = '0'

        function blur() {
            window.clearTimeout(t);
        }

        inp.addEventListener("blur", blur); // 监听blur事件
        document.body.appendChild(inp);
        inp.focus(); // 获取焦点
        setTimeout(function () { // 删除无用的标签
            inp.removeEventListener("blur", blur);
            document.body.removeChild(inp);
        }, 1000);
        //有客户端 如果有本地exe应用,就会弹框,input失去焦点,然后执行blur()事件 清空t定时器 - 删除无用的标签定时器
        //无客户端 不会弹框,input也不会失去焦点 触发t定时器- 执行callback - 删除无用的标签定时器
        location.href = url;
    }
    $scope.copyLink = function (){
        $(document).find('body').eq(0).append('<div id="ngCopyableId">' + window.location.href + '</div>');
        var newElem = angular.element(document.getElementById('ngCopyableId'))[0];

        var range = document.createRange();
        range.selectNode(newElem);
        window.getSelection().removeAllRanges();
        window.getSelection().addRange(range);
        var successful = document.execCommand('copy');

        var oldElem = document.getElementById('ngCopyableId');
        oldElem.parentNode.removeChild(oldElem);
        window.getSelection().removeAllRanges();
    }

上面可以看到未安装的动画加了!appin过滤,因为发现安卓和苹果那边可以做到识别是否安装了动画。因此就不在这里做了。有类似这样的方法去判断:

private boolean schemeValid() {
        PackageManager manager = mContext.getPackageManager();
        Intent action = new Intent(Intent.ACTION_VIEW);
        action.setData(Uri.parse("weixin://"));
        List list = manager.queryIntentActivities(action, PackageManager.GET_RESOLVED_FILTER);
        return list != null && list.size() > 0;
    }
    

总结一下:上面的功能,是一个很简单的分享功能,就是点击分享之后,把当前链接放进剪切板,然后跳转到app应用即可。
但是都是通过其他侧面实现的方式,比如PC端好实现的,在安装了相应的软件之后,点击分享会弹出弹窗,而如果没有安装,则不会弹出,利用这一点,可以通过绑定一个input按钮并且有一个blur事件,因为有弹窗,blur就会失焦。利用这点就可以间接判定是否安装了相应应用,如果没有安装就跳转到相应网页版聊天。这样的方式是有缺点的,如果屏蔽了弹窗,那就这个方法就失效了,还有就是有些浏览器可能不弹窗,目前试了edge、fireFox、chrom都有弹。
​ 移动端的浏览器就是大问题了,因为每个手机的系统版本迭代,有些分享方式就不能适用了。比如,跳转之后,苹果的safari会弹窗拦截,那么用延迟显示实现判断是否安装了应用的方式就不行了,这样一搞就是就算安装了应用,点击打开之后还是会跳转到failUrl或者未安装的下载链接。因此做了一个求其次的方案,就是未安装不再跳转下载url那里,而是换成显示一个未安装标签动画。这样的话就算安装了也会跳转过去,看不到未安装的标签。移动端的主要问题还是苹果那里,安卓测试了下没问题,因为不会弹窗,利用iframe, 使得请求跳转的时候不会中断js。可以把上面aos跳转的failUrl解开注释试一试。ios的话就没用了。
在查资料的时候看到,由于安全隐私的原因,目前网页端无法通过js脚本直接判断某个APP是否已安装,只能首先通过js尝试性的启动app,然后再进入安装流程。启动app的方案有schema,universal link,具体详情请参考openinstall。
如果有什么更好的分享方式,可以评论一下。目前上述的分享很简单,如果要跳转到具体页面拉起被跳转app的分享窗口,可能需要在URl Scheme上面加一些参数,这个得看后面有没有这个需求了。后面加需求的话,只关注pc和移动的浏览器即可,app那边只需传参,让工程师处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值