如何使用钉钉JSApi,获取钉钉定位信息原创
金蝶云社区-吴锐雄
吴锐雄
7人赞赏了该文章 3675次浏览 未经作者许可,禁止转载编辑于2023年09月22日 10:47:39

关键词:移动端,自定义控件,钉钉JSApi(JavaScript Api),定位


一、需求

在钉钉上获取定位信息,弹出手机的“位置信息”权限窗口。开放了 JavaScript接口的 手机app(企业微信,微信,钉钉),如何对手机app的JavaScript Api进行调用


二、思路与方案

  • JavaScript Api,其实就是一个js文件,使用自定义控件加载钉钉开放平台的JSApi。

  • 在苍穹的插件中,调用钉钉提供的接口,获取相关token,生成签名,传递给自定义控件。

  • 在自定义控件中经过鉴权,就可以调用手机app的JSApi了。

  • 苍穹目前针对一些市场占有率比较高的手机app有做jsapi的集成,不需要开发者实现;但是对于那些有api的客户自研app,那么就需要苍穹开发者自行实现jsapi的对接。本篇文章以集成钉钉jsapi为案例,给苍穹开发者们做集成手机app的jsapi提供参考。


三、实现过程

1.开发钉钉首页

开发一个钉钉首页简单拖拽几个按钮,将其命名为:kdec_wrx_mobhome

image.png

在钉钉的开放平台里面,配置这个钉钉首页。

image.png


2.开发一个钉钉上使用的苍穹页面,用来展示定位信息。

拖入以下这几个控件,用来实现定位功能。

按钮控件:命名为“定位”,用来触发按钮点击,点击时调用自定义控件获取定位信息。

自定义控件:加载钉钉的jsapi,调用鉴权接口,调用定位接口。这个自定义控件无界面,因此可以将他的高度宽度设置为0px。

多行文本控件4个:分别用来展示,定位返回的json字符串结果、从json中解析出来的中文地址、经度、维度。

image.png


3.开发自定义控件

index.js部分代码如下:


(1)MyComponent初始化

    MyComponent.prototype = {
        _setModel: function(model) {
            this.model = model
        },
        init: function(props) {
            init(props);
        },
        update: function(props) {
            getLocation(this.model)
        },
        destoryed: function() {

        }
    }


(2)在自定义控件的初始化方法中,引入钉钉的jsapi文件。然后进行 JSAPI鉴权。

鉴权代码,可以参考钉钉文档。dd.config中所有的参数必须直接来自服务端,不能直接在前端定义。

请查看文章第六点参考资料。

    function init(props) {
        loadScript("https://g.alicdn.com/dingding/dingtalk-jsapi/2.10.3/dingtalk.open.js", "loadDDJsApi",
            function() {
                // 开始鉴权
                dd.config({
                    agentId: props.data.agentId, // 必填,微应用ID
                    corpId: props.data.corpId, //必填,企业ID
                    timeStamp: props.data.timeStamp, // 必填,生成签名的时间戳
                    nonceStr: props.data.nonceStr, // 必填,自定义固定字符串。
                    signature: props.data.signature, // 必填,签名
                    type: 0, //选填。0表示微应用的jsapi,1表示服务窗的jsapi;不填默认为0。该参数从dingtalk.js的0.8.3版本开始支持
                    jsApiList: [
                            'runtime.info',
                            'device.geolocation.get'
                            //'biz.contact.choose',
                            //'device.notification.confirm',
                            //'device.notification.alert',
                            //'device.notification.prompt',
                            //'biz.ding.post',
                            //'biz.util.openLink'
                        ] // 必填,需要使用的jsapi列表,注意:不要带dd。
                });

                dd.error(function(err) {
                        alert('dd error: ' + JSON.stringify(err));
                    }) //该方法必须带上,用来捕获鉴权出现的异常信息,否则不方便排查出现的问题

            }
        )
    }


(3)在update方法中,调用钉钉的jsapi接口,获取当前定位信息。

(自定义控件的update方法,当在苍穹插件里面调用 customcontrol.setData方法时,会被触发;

调用model.invoke,会触发苍穹后端插件的customEvent事件)

    function getLocation(model) {
        dd.ready(function() {
            dd.device.geolocation.get({
                targetAccuracy: Number,
                coordinate: Number,
                withReGeocode: Boolean,
                useCache: true, //默认是true,如果需要频繁获取地理位置,请设置false
                onSuccess: function(result) {
                    console.log(result)
                    model.invoke('getLocation', result)

                },
                onFail: function(err) {}
            });
        });
    }



4.开发苍穹插件

以下摘抄自钉钉开放平台文档

dd.config中所有的参数必须直接来自服务端,不能直接在前端定义。因此在苍穹页面插件中,beforeBindData事件里面,获取钉钉的access_token、jsapi_ticket;构建当前url、随机字符串、时间戳等几个参数。

获取自定义控件CustomControl,将参数设置给自定义控件。

(1)构建签名的参数,请查看文章第六点参考资料。

@Override
public void beforeBindData(EventObject e) {
    super.beforeBindData(e);

    // 获取access_token
    String strResAT = requestGetUrl("https://oapi.dingtalk.com/gettoken?appkey=钉钉应用的appkey&appsecret=钉钉应用的appsecret");
    JSONObject jsonResAT = JSONObject.parseObject(strResAT);

    // 获取jsapi_ticket
    String strResTk = requestGetUrl("https://oapi.dingtalk.com/get_jsapi_ticket?access_token=" + jsonResAT.get("access_token").toString());
    JSONObject jsonResTk = JSONObject.parseObject(strResTk);

    // 构建几个签名所需的参数
    // 当前网页的URL,不包含#及其后面部分。
    String currentUrl = "http://172.20.14.63:8085/ierp/mobile.html?apptype=dd&corpid=你的钉钉企业id&appkey=钉钉应用的appkey&agentid=钉钉应用的agentid&appsecret=钉钉应用的appsecret&form=kdec_wrx_mobhome";
    String jsticket = jsonResTk.get("ticket").toString();
    // 随机字符串
    String nonceStr = DdConfigSign.getRandomStr(16);
    // 时间戳
    long timeStamp = new Date().getTime();
    String signStr = "";
    try {
        signStr = DdConfigSign.sign(jsticket, nonceStr, timeStamp, currentUrl);
        System.out.println();
    } catch (Exception exception) {
        throw new RuntimeException(exception);
    }

    CustomControl customcontrol = this.getView().getControl("kdec_customcontrolap");
    Map<String, Object> paramsMap = new HashMap<String, Object>();
    paramsMap.put("agentId", "你的钉钉应用的agentId");
    paramsMap.put("corpId", "你的钉钉企业id");
    paramsMap.put("timeStamp", timeStamp);
    paramsMap.put("nonceStr", nonceStr);
    paramsMap.put("signature", signStr);
    paramsMap.put("type", 0);

    customcontrol.setData(paramsMap);
}


(2)点击按钮时,触发自定义控件的update方法,开始获取定位信息

@Override
public void registerListener(EventObject e) {
    super.registerListener(e);
    addClickListeners("kdec_getlocation");
}

@Override
public void click(EventObject evt) {
    super.click(evt);
    if (evt.getSource() instanceof Control) {
        switch ( ((Control)evt.getSource()).getKey() ) {
            case "kdec_getlocation":
                CustomControl customcontrol = this.getView().getControl("kdec_customcontrolap");
                Map<String, Object> paramsMap = new HashMap<String, Object>();
                customcontrol.setData(paramsMap);
                break;
        }
    }
}


(3)customEvent接收来自自定义控件获取到的地址信息,赋值给几个多行文本字段控件。

@Override
public void customEvent(CustomEventArgs e) {
    super.customEvent(e);

    // 设计器上自定义控件的标识
    String key = e.getKey();
    // 前端通过model.invoke传给后端的数据
    String args = e.getEventArgs();
    // 前端通过model.invoke定义的事件名
    String eventName = e.getEventName();
    System.out.println("自定义控件标识: " + key + ";事件名: " + eventName + ";自定义控件回传参数: " + args);

    JSONObject jsonObject = JSONObject.parseObject(args);

    getModel().setValue("kdec_json", args);
    getModel().setValue("kdec_address", jsonObject.get("address"));
    getModel().setValue("kdec_longitude", jsonObject.get("longitude"));
    getModel().setValue("kdec_latitude", jsonObject.get("latitude"));


}


5.新增自定义控件方案,以及注册苍穹插件

新增自定义控件方案,我将方案命名为"ddjsapi"

image.png

image.png



四,效果图

进入企业应用

image.png

跳转钉钉定位页面

image.png


image.png

image.png



五、开发环境版本

不限


六、注意事项

1.关于本案例的代码简化

为了重点展示jsapi如何鉴权,因此本案例省略了以下几个步骤的代码,请开发者自行实现。


(1)jsapi_ticket可以用苍穹的缓存框架存起来,设置2小时过期时间,

以下摘抄自钉钉文档:

企业内部应用获取jsapi_ticket,一个appKey对应一个jsapi_ticket,所以在使用的时候需要将jsapi_ticket以appKey为维度进行缓存下来(设置缓存过期时间2小时),并不需要每次都通过接口拉取


(2)在插件开发中,我用的是同步阻塞的方式,使用okhttp框架获取响应结果的,实际开发过程中,请开发者采用异步非阻塞的方式获取响应结果。关于http框架,这里仅做一个示例,开发者可以选用自己喜欢的其他http框架。


2.请在钉钉手机app里面访问本案例的苍穹页面。


3.苍穹插件开发,构建当前页面的url,要填写在钉钉应用上配的首页地址。

image.png


4.钉钉的一些重要参考,可以在钉钉登录开发者后台,获取相关应用和企业信息:

image.png

image.png


七、参考资料

钉钉JSAPI鉴权

钉钉定位

钉钉配置








赞 7