本文介绍了如何在钉钉平台上集成JavaScript Api(JSApi)以实现定位功能。文章首先提出需求,即在钉钉上通过JavaScript Api获取定位信息并请求位置权限。随后详细阐述了实现思路与方案,即通过自定义控件加载钉钉JSApi,调用鉴权接口和定位接口。接着,文章分步介绍了实现过程,包括开发钉钉首页和苍穹页面、编写自定义控件的JavaScript代码、以及开发苍穹插件以获取必要参数并构建签名。最后,文章提供了关键代码片段,展示了如何在苍穹插件中通过服务端获取必要的token和ticket,构建签名,并设置给自定义控件。
关键词:移动端,自定义控件,钉钉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
在钉钉的开放平台里面,配置这个钉钉首页。
2.开发一个钉钉上使用的苍穹页面,用来展示定位信息。
拖入以下这几个控件,用来实现定位功能。
按钮控件:命名为“定位”,用来触发按钮点击,点击时调用自定义控件获取定位信息。
自定义控件:加载钉钉的jsapi,调用鉴权接口,调用定位接口。这个自定义控件无界面,因此可以将他的高度宽度设置为0px。
多行文本控件4个:分别用来展示,定位返回的json字符串结果、从json中解析出来的中文地址、经度、维度。
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"
四,效果图
进入企业应用
跳转钉钉定位页面
五、开发环境版本
不限
六、注意事项
1.关于本案例的代码简化
为了重点展示jsapi如何鉴权,因此本案例省略了以下几个步骤的代码,请开发者自行实现。
(1)jsapi_ticket可以用苍穹的缓存框架存起来,设置2小时过期时间,
以下摘抄自钉钉文档:
企业内部应用获取jsapi_ticket,一个appKey对应一个jsapi_ticket,所以在使用的时候需要将jsapi_ticket以appKey为维度进行缓存下来(设置缓存过期时间2小时),并不需要每次都通过接口拉取。
(2)在插件开发中,我用的是同步阻塞的方式,使用okhttp框架获取响应结果的,实际开发过程中,请开发者采用异步非阻塞的方式获取响应结果。关于http框架,这里仅做一个示例,开发者可以选用自己喜欢的其他http框架。
2.请在钉钉手机app里面访问本案例的苍穹页面。
3.苍穹插件开发,构建当前页面的url,要填写在钉钉应用上配的首页地址。
4.钉钉的一些重要参考,可以在钉钉登录开发者后台,获取相关应用和企业信息:
七、参考资料
dd_getlocation.zip(20.31KB)
推荐阅读