网页调取APP
23 February 2015

其实高德地图、百度地图的JS API写的很清楚,但是对于如何调用,没玩过的会觉得有点迷茫,最近项目要调用地图,我也是看了半天,才理解为何网页能有如此的能耐调用手机内安装的APP。

基础篇

我们能在浏览器内跳转网页是http、https协议,能打开本地文件是file协议,调用APP用的是scheme协议或者intent协议,其实都是发送请求,获得响应,只是网页和APP是使用这两个协议通信的。scheme协议不仅仅用于ios端,也适用于安卓。但intent只适用于安卓。

1、scheme协议

在 iOS 里,程序之间都是相互隔离,目前并没有一个有效的方式来做程序间通信,幸好 iOS 程序可以很方便的注册自己的 URL Scheme,这样就可以通过打开特定 URL 的方式来传递参数给另外一个程序。原生的APP和网页通过这种协议可以互相通信,safari或者APP的webView都可以识别该协议(一些浏览器如微信内置浏览器和QQ浏览器不支持,据后台技术哥哥介绍这是腾讯有意屏蔽,默认的webview控件是支持的).

如果是自己的APP想被网页调用,需要自己在app中注册scheme,这不是我研究的范畴。。。

我们一般是调用别人的APP,会使用scheme协议就行,其实特简单,通过链接就可以

常用APP的scheme

QQ mqq://
微信 weixin://
淘宝 taobao://
大众点评 dianping:// dianping://search
新浪微博 sinaweibo://
支付宝 alipay://
豆瓣fm doubanradio://
美团 imeituan://
1号店 wccbyihaodian://
有道词典yddictproapp://
知乎 zhihu://
优酷 youku://

见知乎上的整理:http://www.zhihu.com/question/19907735

2、intent协议

“在一个Android应用中,主要是由四种组件组成的,这四种组件可参考“Android应用的构成”。而这四种组件是独立的,它们之间可以互相调用,协调工作,最终组成一个真正的Android应用。在这些组件之间的通讯中,主要是由Intent协助完成的。Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。”所以说intent是协议是不准确的,intent实际上是一种在不同组件之间传递的请求信息。

示例:网页调取百度地图、高德地图

官方文档:

1、高德地图:http://lbs.amap.com/api/uri-api/ios-uri-explain/

2、百度地图:http://developer.baidu.com/map/index.php?title=uri/api/ios

例如调用常规线路规划导航:

scheme调用

高德地图:

<a href="iosamap://path?sourceApplication=applicationName&backScheme=applicationScheme&sid=BGVIS1&slat=39.92848272&slon=116.39560823&sname=A&did=BGVIS2&dlat=39.98848272&dlon=116.47560823&dname=B&dev=0&m=0&t=0">公交导航</a>

百度地图:

<a href="baidumap://map/direction?origin=34.264642646862,108.95108518068&destination=40.007623,116.360582&mode=driving&src=yourCompanyName|yourAppName">驾车导航</a>

intent调用

高德地图:

<a href="androidamap://route?sourceApplication=softname&slat=36.2&slon=116.1&sname=abc&dlat=36.3&dlon=116.2&dname=def&dev=0&m=0&t=1&showType=1">线路规划</a>

百度地图:

<a href="intent://map/direction?origin=latlng:34.264642646862,108.95108518068|name:我家&destination=大雁塔&mode=driving&region=西安&src=yourCompanyName|yourAppName">线路规划</a>

注意:有些安卓机型上面2种方式都不适用。。。

习惯性贴代码:

    <script type="text/javascript" src="js/map.js"></script>

    <script type="text/javascript">
        var mapName = [amap,baidumap];
        var iosScheme = [];
        var androidIntent = [];
        iosScheme[0] = 'iosamap://path?sourceApplication=huiyouxing&backScheme=applicationScheme&sid=BGVIS1&slat=&slon=&sname=&did=BGVIS2&dlat='+initPosition.lat+'&dlon='+initPosition.lng+'&dname='+positionName+'&dev=0&m=0&t=0';

        iosScheme[1] = 'baidumap://map/direction?origin='+myLocation.lat+','+myLocation.lng+'&destination='+initPosition.lat+','+initPosition.lng+'&mode=driving&src=huiyouxing';

        androidIntent[0] = 'androidamap://route?sourceApplication=huiyouxing&slat='+myLocation.lat+'&slon='+myLocation.lng+'&sname=起点&dlat='+initPosition.lat+'&dlon='+initPosition.lng+'&dname='+positionName+'&dev=0&m=0&t=1&showType=1';
        androidIntent[1] = 'intent://map/direction?origin=latlng:'+myLocation.lat+','+myLocation.lng+'|name:起点&destination='+initPosition.lat+','+initPosition.lng+'&mode=driving&src=huiyouxing';

        window.mapCallNode=document.querySelectorAll('.callMap');

        if (typeof mapApp !== 'object') {
            mapApp = {};
        }

        (function () {
            var ua = navigator.userAgent.toLowerCase(),
            locked = false,
            domLoaded = document.readyState==='complete',
            delayToRun;

            function getAndroidVersion() {
                var match = ua.match(/android\s([0-9\.]*)/);
                return match ? match[1] : false;
            }

            var noIntentTest = /360 aphone|weibo|windvane/.test(ua);
            var hasIntentTest = /chrome|samsung/.test(ua);
            var isAndroid = /android|adr/.test(ua);
            var canIntent = !noIntentTest && hasIntentTest && isAndroid;
            var openInIfr = /weibo|m353/.test(ua);
            var inWeibo = ua.indexOf('weibo')>-1;

            //魅族
            if (ua.indexOf('m353')>-1 && !noIntentTest) {
                canIntent = false;
            }

            mapApp.open = function (params, mapDom) {
                if (!domLoaded && (ua.indexOf('360 aphone')>-1 || canIntent)) {
                    var arg = arguments;
                    delayToRun = function () {
                        AlipayWallet.open.apply(null, arg);
                        delayToRun = null;
                    };
                    return;
                }

                //问题来了:小米使用mapScheme,但是不能调用高德地图
                // 通过scheme协议唤起地图
                if (!canIntent) {
                    var mapScheme = iosScheme[params];
                    var openSchemeLink = mapDom;
                    openSchemeLink.href = mapScheme;
                    // 执行click
                    //openSchemeLink.dispatchEvent(customClickEvent());
                    

                } else {
                    // android 下 通过 intent 协议唤起钱包
                    var mapIntent = androidIntent[params];
                    var openSchemeLink = mapDom;
                    openIntentLink.href = intentUrl;
                    // 执行click
                    //openIntentLink.dispatchEvent(customClickEvent());
                }

            }

            if (!domLoaded) {
                document.addEventListener('DOMContentLoaded', function () {
                    domLoaded = true;
                    if (typeof delayToRun === 'function') {
                        delayToRun();
                    }
                }, false);
            }
        })();
    </script>